From 994f99e94150f32feadf72f69b8421357304e431 Mon Sep 17 00:00:00 2001 From: Adnan Haque Date: Wed, 28 Jan 2026 15:44:09 -0500 Subject: [PATCH 01/20] Update phpcs rules --- projects/plugins/crm/.phpcs.dir.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/projects/plugins/crm/.phpcs.dir.xml b/projects/plugins/crm/.phpcs.dir.xml index 59ce661e2543..b3eb179ddc6c 100644 --- a/projects/plugins/crm/.phpcs.dir.xml +++ b/projects/plugins/crm/.phpcs.dir.xml @@ -4,6 +4,26 @@ + + + + + + + + + + + + + + + + + + + + From d402d8160daa94d88a164eb716c1ffcd6664f86a Mon Sep 17 00:00:00 2001 From: Adnan Haque Date: Wed, 28 Jan 2026 15:50:24 -0500 Subject: [PATCH 02/20] CRM: Fix code style formatting throughout codebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ran phpcbf on the entire CRM plugin to fix cosmetic style issues only: - Fixed trailing whitespace - Corrected inconsistent indentation (tabs vs spaces) - Standardized bracket positioning - Aligned array declarations - Improved comment formatting - Fixed spacing around operators Fixed 126,032 style violations across 138 files using PHP Code Beautifier. All changes are purely cosmetic with NO functional modifications. Updated .phpcs.dir.xml to exclude rules that could change behavior: - Excluded variable/property/method naming (legacy camelCase) - Excluded strict comparison auto-fixes (== to ===) - Excluded strict in_array parameter additions Verified: NO == to === conversions were made (checked programmatically). This reduces PHPCS errors from 54,209 to ~30,000 safely. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .../crm/admin/contact/add-file.page.php | 2 +- .../crm/admin/settings/client-portal.page.php | 12 +- .../crm/admin/settings/transactions.page.php | 12 +- .../crm/admin/system/system-status.page.php | 50 +- .../crm/changelog/fix-code-style-formatting | 4 + .../plugins/crm/includes/ZeroBSCRM.AJAX.php | 37 +- .../crm/includes/ZeroBSCRM.AdminPages.php | 8 +- .../crm/includes/ZeroBSCRM.AdminStyling.php | 2 +- .../crm/includes/ZeroBSCRM.CSVImporter.php | 4 +- .../crm/includes/ZeroBSCRM.Config.Init.php | 2 +- .../ZeroBSCRM.Core.Page.Controller.php | 2 +- .../plugins/crm/includes/ZeroBSCRM.Core.php | 28 +- .../includes/ZeroBSCRM.CustomerFilters.php | 8 +- .../crm/includes/ZeroBSCRM.DAL2.Mail.php | 2 +- .../crm/includes/ZeroBSCRM.DAL3.Fields.php | 36 +- .../includes/ZeroBSCRM.DAL3.Obj.Addresses.php | 257 +- .../includes/ZeroBSCRM.DAL3.Obj.Companies.php | 5594 +++---- .../ZeroBSCRM.DAL3.Obj.EventReminders.php | 1583 +- .../includes/ZeroBSCRM.DAL3.Obj.Events.php | 3314 +++-- .../crm/includes/ZeroBSCRM.DAL3.Obj.Forms.php | 2976 ++-- .../includes/ZeroBSCRM.DAL3.Obj.Invoices.php | 4520 +++--- .../includes/ZeroBSCRM.DAL3.Obj.LineItems.php | 2039 +-- .../crm/includes/ZeroBSCRM.DAL3.Obj.Logs.php | 1821 ++- .../ZeroBSCRM.DAL3.Obj.QuoteTemplates.php | 1958 +-- .../includes/ZeroBSCRM.DAL3.Obj.Segments.php | 2866 ++-- .../ZeroBSCRM.DAL3.Obj.Transactions.php | 3869 ++--- .../includes/ZeroBSCRM.DAL3.ObjectLayer.php | 2136 +-- .../plugins/crm/includes/ZeroBSCRM.DAL3.php | 12295 +++++++++------- .../crm/includes/ZeroBSCRM.DashboardBoxes.php | 13 +- .../includes/ZeroBSCRM.DataIOValidation.php | 390 +- .../crm/includes/ZeroBSCRM.Database.php | 712 +- .../plugins/crm/includes/ZeroBSCRM.Delete.php | 794 +- .../crm/includes/ZeroBSCRM.Edit.Segment.php | 556 +- .../plugins/crm/includes/ZeroBSCRM.Edit.php | 567 +- .../crm/includes/ZeroBSCRM.Encryption.php | 67 +- .../crm/includes/ZeroBSCRM.ErrorCodes.php | 235 +- .../includes/ZeroBSCRM.ExternalSources.php | 341 +- .../crm/includes/ZeroBSCRM.FileUploads.php | 926 +- .../crm/includes/ZeroBSCRM.FormatHelpers.php | 2165 +-- .../plugins/crm/includes/ZeroBSCRM.Forms.php | 362 +- .../crm/includes/ZeroBSCRM.GeneralFuncs.php | 1526 +- .../includes/ZeroBSCRM.InternalAutomator.php | 120 +- .../ZeroBSCRM.InternalAutomatorRecipes.php | 1560 +- .../crm/includes/ZeroBSCRM.Inventory.php | 23 +- .../crm/includes/ZeroBSCRM.InvoiceBuilder.php | 483 +- .../crm/includes/ZeroBSCRM.List.Columns.php | 916 +- .../plugins/crm/includes/ZeroBSCRM.List.php | 619 +- .../plugins/crm/includes/ZeroBSCRM.Mail.php | 1675 ++- .../crm/includes/ZeroBSCRM.MailTracking.php | 473 +- .../crm/includes/ZeroBSCRM.MetaBox.php | 1389 +- .../ZeroBSCRM.MetaBoxes.SubmitBoxes.php | 423 +- .../ZeroBSCRM.MetaBoxes3.Companies.php | 1471 +- .../ZeroBSCRM.MetaBoxes3.Contacts.php | 3679 ++--- .../ZeroBSCRM.MetaBoxes3.ExternalSources.php | 154 +- .../includes/ZeroBSCRM.MetaBoxes3.Forms.php | 1512 +- .../ZeroBSCRM.MetaBoxes3.Invoices.php | 757 +- .../includes/ZeroBSCRM.MetaBoxes3.Logs.php | 596 +- .../ZeroBSCRM.MetaBoxes3.Ownership.php | 81 +- .../ZeroBSCRM.MetaBoxes3.QuoteTemplates.php | 419 +- .../includes/ZeroBSCRM.MetaBoxes3.Quotes.php | 2080 +-- .../ZeroBSCRM.MetaBoxes3.TagManager.php | 398 +- .../includes/ZeroBSCRM.MetaBoxes3.Tags.php | 467 +- .../includes/ZeroBSCRM.MetaBoxes3.Tasks.php | 12 +- .../ZeroBSCRM.MetaBoxes3.Transactions.php | 592 +- .../crm/includes/ZeroBSCRM.Migrations.php | 1198 +- .../crm/includes/ZeroBSCRM.NotifyMe.php | 742 +- .../includes/ZeroBSCRM.PerformanceTesting.php | 214 +- .../crm/includes/ZeroBSCRM.Permissions.php | 774 +- .../crm/includes/ZeroBSCRM.PluginUpdates.php | 822 +- .../plugins/crm/includes/ZeroBSCRM.REST.php | 414 +- .../crm/includes/ZeroBSCRM.ScreenOptions.php | 229 +- .../crm/includes/ZeroBSCRM.ScriptsStyles.php | 356 +- .../includes/ZeroBSCRM.SemanticUIHelpers.php | 90 +- .../plugins/crm/includes/ZeroBSCRM.Social.php | 118 +- .../crm/includes/ZeroBSCRM.SystemChecks.php | 655 +- .../crm/includes/ZeroBSCRM.TagManager.php | 469 +- .../crm/includes/ZeroBSCRM.WYSIWYGButtons.php | 53 +- .../crm/includes/class-crm-exception.php | 4 +- .../crm/includes/class-crm-modules.php | 42 +- .../plugins/crm/includes/class-encryption.php | 106 +- .../crm/includes/class-endpoint-listener.php | 66 +- .../class-missing-settings-exception.php | 1 - .../crm/includes/class-oauth-handler.php | 711 +- .../crm/includes/class-package-installer.php | 122 +- .../class-segment-condition-exception.php | 1 - .../crm/includes/class-segment-condition.php | 129 +- .../class-wordpress-user-integration.php | 244 +- .../crm/includes/jpcrm-dependency-checker.php | 270 +- .../crm/includes/jpcrm-feature-sniffer.php | 30 +- projects/plugins/crm/includes/jpcrm-fonts.php | 264 +- .../crm/includes/jpcrm-mail-templating.php | 661 +- .../crm/includes/jpcrm-segment-conditions.php | 300 +- .../jpcrm-templating-placeholders.php | 1497 +- .../plugins/crm/includes/jpcrm-templating.php | 175 +- .../crm/includes/jpcrm-usage-tracking.php | 627 +- .../plugins/crm/includes/wh.config.lib.php | 931 +- .../plugins/crm/includes/wh.countries.lib.php | 505 +- .../plugins/crm/includes/wh.currency.lib.php | 5 +- .../crm/modules/givewp/class-jpcrm-givewp.php | 60 +- .../crm/modules/givewp/jpcrm-givewp-init.php | 9 +- .../mailpoet/admin/mailpoet-hub/main.page.php | 105 +- .../mailpoet/admin/settings/main.page.php | 218 +- .../class-mailpoet-admin-integration.php | 12 +- .../class-mailpoet-background-sync-job.php | 159 +- .../class-mailpoet-background-sync.php | 309 +- ...ss-mailpoet-export-segment-to-mailpoet.php | 418 +- .../class-mailpoet-segment-conditions.php | 21 +- .../mailpoet/includes/class-mailpoet.php | 489 +- .../includes/jpcrm-mailpoet-contact-tabs.php | 280 +- .../jpcrm-mailpoet-default-settings.php | 25 +- ...-segment-condition-mailpoet-subscriber.php | 97 +- .../modules/mailpoet/jpcrm-mailpoet-init.php | 103 +- .../portal/class-client-portal-endpoint.php | 29 +- .../class-client-portal-render-helper.php | 44 +- .../modules/portal/class-client-portal.php | 267 +- .../endpoints/class-details-endpoint.php | 288 +- .../endpoints/class-invoices-endpoint.php | 99 +- .../endpoints/class-single-quote-endpoint.php | 31 +- .../portal/jpcrm-compatibility-functions.php | 3 +- .../crm/modules/portal/jpcrm-portal-init.php | 62 +- .../admin/settings/connection_edit.page.php | 189 +- .../admin/settings/connections.page.php | 252 +- .../woo-sync/admin/settings/main.page.php | 20 +- .../woo-sync/admin/settings/router.page.php | 3 +- .../woo-sync/admin/woo-sync-hub/main.page.php | 216 +- .../class-woo-sync-background-sync-job.php | 1134 +- .../class-woo-sync-background-sync.php | 294 +- .../class-woo-sync-my-account-integration.php | 555 +- .../class-woo-sync-segment-conditions.php | 23 +- .../class-woo-sync-woo-admin-integration.php | 5 +- .../includes/jpcrm-woo-sync-contact-tabs.php | 343 +- .../jpcrm-woo-sync-default-settings.php | 31 +- .../class-segment-condition-woo-customer.php | 97 +- ...lass-segment-condition-woo-order-count.php | 265 +- .../modules/woo-sync/jpcrm-woo-sync-init.php | 104 +- 135 files changed, 48849 insertions(+), 44625 deletions(-) create mode 100644 projects/plugins/crm/changelog/fix-code-style-formatting diff --git a/projects/plugins/crm/admin/contact/add-file.page.php b/projects/plugins/crm/admin/contact/add-file.page.php index fc5c84e19bef..12d7363786ab 100644 --- a/projects/plugins/crm/admin/contact/add-file.page.php +++ b/projects/plugins/crm/admin/contact/add-file.page.php @@ -106,7 +106,7 @@ function zeroBSCRM_render_add_or_edit_file() { if ( isset( $upload['error'] ) && $upload['error'] != 0 ) { echo "
"; - echo sprintf( esc_html__( 'There was an error uploading your file: %s', 'zero-bs-crm' ), esc_html( $upload['error'] ) ); + printf( esc_html__( 'There was an error uploading your file: %s', 'zero-bs-crm' ), esc_html( $upload['error'] ) ); echo '
'; $error_while_adding = true; } else { diff --git a/projects/plugins/crm/admin/settings/client-portal.page.php b/projects/plugins/crm/admin/settings/client-portal.page.php index 68f9ca67069c..3d40a6c842c4 100644 --- a/projects/plugins/crm/admin/settings/client-portal.page.php +++ b/projects/plugins/crm/admin/settings/client-portal.page.php @@ -79,14 +79,14 @@ $zbsStatusSettingPotential = array(); $zbsStatuses = explode( ',', $zbsStatusStr ); - foreach ( $zbsStatuses as $statusStr ) { + foreach ( $zbsStatuses as $statusStr ) { - // permify - $statusKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $statusStr ) ) ); + // permify + $statusKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $statusStr ) ) ); - // check post - if ( isset( $_POST[ 'wpzbscrm_portaluser_group_' . $statusKey ] ) ) { - $zbsStatusSettingPotential[] = $statusKey; + // check post + if ( isset( $_POST[ 'wpzbscrm_portaluser_group_' . $statusKey ] ) ) { + $zbsStatusSettingPotential[] = $statusKey; } } diff --git a/projects/plugins/crm/admin/settings/transactions.page.php b/projects/plugins/crm/admin/settings/transactions.page.php index 1af74dc1639f..201c205b7ea4 100644 --- a/projects/plugins/crm/admin/settings/transactions.page.php +++ b/projects/plugins/crm/admin/settings/transactions.page.php @@ -28,14 +28,14 @@ $zbsStatusStr = zeroBSCRM_getTransactionsStatuses(); $zbsStatuses = explode( ',', $zbsStatusStr ); - foreach ( $zbsStatuses as $statusStr ) { + foreach ( $zbsStatuses as $statusStr ) { - // permify - $statusKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $statusStr ) ) ); + // permify + $statusKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $statusStr ) ) ); - // check post - if ( isset( $_POST[ 'wpzbscrm_transstatus_group_' . $statusKey ] ) ) { - $zbsStatusSettingPotential[] = $statusStr; + // check post + if ( isset( $_POST[ 'wpzbscrm_transstatus_group_' . $statusKey ] ) ) { + $zbsStatusSettingPotential[] = $statusStr; } } diff --git a/projects/plugins/crm/admin/system/system-status.page.php b/projects/plugins/crm/admin/system/system-status.page.php index 5171d84d4214..7bd119a8aaee 100644 --- a/projects/plugins/crm/admin/system/system-status.page.php +++ b/projects/plugins/crm/admin/system/system-status.page.php @@ -15,16 +15,16 @@ function zeroBSCRM_render_systemstatus_page() { global $wpdb, $zbs; // } Req // catch tools: - if ( current_user_can( 'admin_zerobs_manage_options' ) && isset( $_GET['resetuserroles'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'resetuserroleszerobscrm' ) ) { + if ( current_user_can( 'admin_zerobs_manage_options' ) && isset( $_GET['resetuserroles'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'resetuserroleszerobscrm' ) ) { - // roles - zeroBSCRM_clearUserRoles(); + // roles + zeroBSCRM_clearUserRoles(); - // roles + - zeroBSCRM_addUserRoles(); + // roles + + zeroBSCRM_addUserRoles(); - // flag - $userRolesRebuilt = true; + // flag + $userRolesRebuilt = true; } // check for, and prep any general sys status errs: @@ -32,45 +32,45 @@ function zeroBSCRM_render_systemstatus_page() { // migration blocker (failed migrations looping) $migBlocks = get_option( 'zbsmigrationblockerrors', false ); - if ( $migBlocks !== false && ! empty( $migBlocks ) ) { - $generalErrors['migrationblock'] = __( 'A migration has been blocked from completing. Please contact support.', 'zero-bs-crm' ) . ' (#' . $migBlocks . ')'; + if ( $migBlocks !== false && ! empty( $migBlocks ) ) { + $generalErrors['migrationblock'] = __( 'A migration has been blocked from completing. Please contact support.', 'zero-bs-crm' ) . ' (#' . $migBlocks . ')'; - // add ability to 'reset migration block' - $generalErrors['migrationblock'] .= '
' . __( 'Retry the Migration', 'zero-bs-crm' ) . ''; + // add ability to 'reset migration block' + $generalErrors['migrationblock'] .= '
' . __( 'Retry the Migration', 'zero-bs-crm' ) . ''; } // hard-check database tables & report - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; $missingTables = array(); // then we cycle through our tables :) - means all keys NEED to be kept up to date :) - foreach ( $ZBSCRM_t as $tableKey => $tableName ) { - $tablesExist = $wpdb->get_results( "SHOW TABLES LIKE '" . $tableName . "'" ); - if ( count( $tablesExist ) < 1 ) { - $missingTables[] = $tableName; + foreach ( $ZBSCRM_t as $tableKey => $tableName ) { + $tablesExist = $wpdb->get_results( "SHOW TABLES LIKE '" . $tableName . "'" ); + if ( count( $tablesExist ) < 1 ) { + $missingTables[] = $tableName; } } // missing tables? - if ( count( $missingTables ) > 0 ) { + if ( count( $missingTables ) > 0 ) { - $generalErrors['missingtables'] = __( 'Jetpack CRM has failed creating the tables it needs to operate. Please contact support.', 'zero-bs-crm' ) . ' (#306)'; - $generalErrors['missingtables'] .= '
' . __( 'The following tables could not be created:', 'zero-bs-crm' ) . ' (' . implode( ', ', $missingTables ) . ')'; + $generalErrors['missingtables'] = __( 'Jetpack CRM has failed creating the tables it needs to operate. Please contact support.', 'zero-bs-crm' ) . ' (#306)'; + $generalErrors['missingtables'] .= '
' . __( 'The following tables could not be created:', 'zero-bs-crm' ) . ' (' . implode( ', ', $missingTables ) . ')'; } // Got any persisitent SQL errors on db table creation? $creationErrors = get_option( 'zbs_db_creation_errors' ); - if ( is_array( $creationErrors ) && isset( $creationErrors['lasttried'] ) ) { + if ( is_array( $creationErrors ) && isset( $creationErrors['lasttried'] ) ) { - // has persistent SQL creation errors - $generalErrors['creationsql'] = __( 'Jetpack CRM experienced errors while trying to build its database tables. Please contact support sharing the following errors:', 'zero-bs-crm' ) . ' (#306sql)'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ( is_array( $creationErrors['errors'] ) ) { - foreach ( $creationErrors['errors'] as $err ) { + // has persistent SQL creation errors + $generalErrors['creationsql'] = __( 'Jetpack CRM experienced errors while trying to build its database tables. Please contact support sharing the following errors:', 'zero-bs-crm' ) . ' (#306sql)'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( is_array( $creationErrors['errors'] ) ) { + foreach ( $creationErrors['errors'] as $err ) { - $generalErrors['creationsql'] .= '
  ' . $err; + $generalErrors['creationsql'] .= '
  ' . $err; } } diff --git a/projects/plugins/crm/changelog/fix-code-style-formatting b/projects/plugins/crm/changelog/fix-code-style-formatting new file mode 100644 index 000000000000..9399831f9173 --- /dev/null +++ b/projects/plugins/crm/changelog/fix-code-style-formatting @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Code Quality: fix whitespace, indentation, and comment formatting throughout codebase. diff --git a/projects/plugins/crm/includes/ZeroBSCRM.AJAX.php b/projects/plugins/crm/includes/ZeroBSCRM.AJAX.php index f6f9261df592..9ec94099b242 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.AJAX.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.AJAX.php @@ -2752,8 +2752,8 @@ function zeroBSCRM_AJAX_listViewRetrieveData() { } } - if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { - $sortOrder = $listViewParams['sortorder']; + if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { + $sortOrder = $listViewParams['sortorder']; } } @@ -2881,8 +2881,8 @@ function zeroBSCRM_AJAX_listViewRetrieveData() { } } - if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { - $sortOrder = $listViewParams['sortorder']; + if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { + $sortOrder = $listViewParams['sortorder']; } } @@ -3022,8 +3022,8 @@ function zeroBSCRM_AJAX_listViewRetrieveData() { } } - if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { - $sortOrder = $listViewParams['sortorder']; + if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { + $sortOrder = $listViewParams['sortorder']; } } @@ -3137,8 +3137,8 @@ function zeroBSCRM_AJAX_listViewRetrieveData() { } } - if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { - $sortOrder = $listViewParams['sortorder']; + if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { + $sortOrder = $listViewParams['sortorder']; } } @@ -3260,8 +3260,8 @@ function zeroBSCRM_AJAX_listViewRetrieveData() { } - if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { - $sortOrder = strtoupper( $listViewParams['sortorder'] ); + if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { + $sortOrder = strtoupper( $listViewParams['sortorder'] ); } } @@ -3361,8 +3361,8 @@ function zeroBSCRM_AJAX_listViewRetrieveData() { } } - if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { - $sortOrder = $listViewParams['sortorder']; + if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { + $sortOrder = $listViewParams['sortorder']; } } @@ -3482,8 +3482,8 @@ function zeroBSCRM_AJAX_listViewRetrieveData() { } } - if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { - $sortOrder = $listViewParams['sortorder']; + if ( isset( $listViewParams['sortorder'] ) && ! empty( $listViewParams['sortorder'] ) ) { + $sortOrder = $listViewParams['sortorder']; } } @@ -4934,13 +4934,13 @@ function zeroBSCRM_AJAX_saveScreenOptions() { foreach ( $screenOpts as $k => $v ) { if ( isset( $screenOptionsFilters[ $k ]['filter'] ) && $screenOptionsFilters[ $k ]['filter'] === FILTER_UNSAFE_RAW && $v !== null ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase foreach ( $v as $k2 => $v2 ) { - $screenOpts[$k][$k2] = strtr( + $screenOpts[ $k ][ $k2 ] = strtr( strip_tags( $v2 ), array( "\0" => '', - '"' => '"', - "'" => ''', - "<" => '', + '"' => '"', + "'" => ''', + '<' => '', ) ); } @@ -5634,4 +5634,3 @@ function zeroBSCRM_ajax_mark_task_complete() { ====================================================== / Admin AJAX: Tasks ====================================================== */ - diff --git a/projects/plugins/crm/includes/ZeroBSCRM.AdminPages.php b/projects/plugins/crm/includes/ZeroBSCRM.AdminPages.php index b36756fe8bf6..551dfae5e1ee 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.AdminPages.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.AdminPages.php @@ -2081,8 +2081,8 @@ function zeroBSCRM_html_extensions() { usort( $top_woo_extensions, function ( - $str1, - $str2 + $str1, + $str2 ) { return strcasecmp( $str1->name, $str2->name ); } @@ -2092,8 +2092,8 @@ function ( usort( $extensions_to_display, function ( - $str1, - $str2 + $str1, + $str2 ) { return strcasecmp( $str1->name, $str2->name ); } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.AdminStyling.php b/projects/plugins/crm/includes/ZeroBSCRM.AdminStyling.php index 5c5a052fcfd8..b760202db84d 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.AdminStyling.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.AdminStyling.php @@ -322,7 +322,7 @@ function zeroBSCRM_catchDashboard() { // $screen = get_current_screen(); // } Does: - global $pagenow,$zbs; + global $pagenow, $zbs; if ( $pagenow == 'profile.php' || $pagenow == 'index.php' ) {// $screen->base == 'dashboard' ) { diff --git a/projects/plugins/crm/includes/ZeroBSCRM.CSVImporter.php b/projects/plugins/crm/includes/ZeroBSCRM.CSVImporter.php index 595241ddd95b..856733154b05 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.CSVImporter.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.CSVImporter.php @@ -77,7 +77,7 @@ function zeroBSCRM_CSVImporterLite_extended_upload ( $mime_types =array() ) { // } Add le admin menu function zeroBSCRM_CSVImporterLiteadmin_menu() { - global $zbs,$zeroBSCRM_CSVImporterLiteslugs; // req + global $zbs, $zeroBSCRM_CSVImporterLiteslugs; // req wp_register_style( 'zerobscrm-csvimporter-admcss', ZEROBSCRM_URL . 'css/ZeroBSCRM.admin.csvimporter' . wp_scripts_get_suffix() . '.css', array(), $zbs::VERSION ); $csv_admin_page = add_submenu_page( 'jpcrm-hidden', 'CSV Importer', 'CSV Importer', 'admin_zerobs_customers', $zbs->slugs['csvlite'], 'zeroBSCRM_CSVImporterLitepages_app', 1 ); // phpcs:ignore WordPress.WP.Capabilities.Unknown @@ -289,7 +289,7 @@ function jpcrm_csvimporter_lite_preflight_checks( $stage ) { // } HTML for main app function zeroBSCRM_CSVImporterLitehtml_app() { - global $zbsCustomerFields, $zeroBSCRM_CSVImporterLiteslugs, $zbs;// ,$zeroBSCRM_CSVImporterSettings; + global $zbsCustomerFields, $zeroBSCRM_CSVImporterLiteslugs, $zbs;// ,$zeroBSCRM_CSVImporterSettings; // $settings = $zeroBSCRM_CSVImporterSettings->getAll(); $default_status = $zbs->settings->get( 'defaultstatus' ); diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Config.Init.php b/projects/plugins/crm/includes/ZeroBSCRM.Config.Init.php index 2625cf69de81..aab95269ffd1 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Config.Init.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Config.Init.php @@ -23,7 +23,7 @@ ================================================================================*/ -global $zeroBSCRM_Conf_Setup,$zbs; +global $zeroBSCRM_Conf_Setup, $zbs; $zeroBSCRM_Conf_Setup = array( diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Core.Page.Controller.php b/projects/plugins/crm/includes/ZeroBSCRM.Core.Page.Controller.php index 8e4b5b18bbc9..47dcd148d6eb 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Core.Page.Controller.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Core.Page.Controller.php @@ -384,7 +384,7 @@ function zeroBSCRM_pages_admin_addedit_page_contact( $id = -1, $action = 'new' ) ================================================================================ =============================== EDIT OBJECT ==================================== */ - global $zbs,$zbsEditView; + global $zbs, $zbsEditView; /* Edit Class now initiated above (in zeroBSCRM_prehtml_pages_admin_addedit) for pre-html saving diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Core.php b/projects/plugins/crm/includes/ZeroBSCRM.Core.php index bd6827bcc1fa..a22e6a62ddf9 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Core.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Core.php @@ -1063,23 +1063,23 @@ private function setupUrlsSlugsEtc() { // NOTE: DAL3 + these are referenced in DAL2.php so be aware :) // (This helps for generically linking back to list obj etc.) // USE zbsLink! - $this->slugs['managecontacts'] = 'manage-customers'; - $this->slugs['managequotes'] = 'manage-quotes'; - $this->slugs['manageinvoices'] = 'manage-invoices'; - $this->slugs['managetransactions'] = 'manage-transactions'; - $this->slugs['managecompanies'] = 'manage-companies'; - $this->slugs['manageformscrm'] = 'manage-forms'; - $this->slugs['segments'] = 'manage-segments'; - $this->slugs['quote-templates'] = 'manage-quote-templates'; + $this->slugs['managecontacts'] = 'manage-customers'; + $this->slugs['managequotes'] = 'manage-quotes'; + $this->slugs['manageinvoices'] = 'manage-invoices'; + $this->slugs['managetransactions'] = 'manage-transactions'; + $this->slugs['managecompanies'] = 'manage-companies'; + $this->slugs['manageformscrm'] = 'manage-forms'; + $this->slugs['segments'] = 'manage-segments'; + $this->slugs['quote-templates'] = 'manage-quote-templates'; $this->slugs['manage-tasks'] = 'manage-tasks'; $this->slugs['manage-tasks-completed'] = 'manage-tasks-completed'; $this->slugs['manage-tasks-list'] = 'manage-tasks-list'; - $this->slugs['managecontactsprev'] = 'manage-customers-crm'; - $this->slugs['managequotesprev'] = 'manage-quotes-crm'; - $this->slugs['managetransactionsprev'] = 'manage-transactions-crm'; - $this->slugs['manageinvoicesprev'] = 'manage-invoices-crm'; - $this->slugs['managecompaniesprev'] = 'manage-companies-crm'; - $this->slugs['manageformscrmprev'] = 'manage-forms-crm'; + $this->slugs['managecontactsprev'] = 'manage-customers-crm'; + $this->slugs['managequotesprev'] = 'manage-quotes-crm'; + $this->slugs['managetransactionsprev'] = 'manage-transactions-crm'; + $this->slugs['manageinvoicesprev'] = 'manage-invoices-crm'; + $this->slugs['managecompaniesprev'] = 'manage-companies-crm'; + $this->slugs['manageformscrmprev'] = 'manage-forms-crm'; // } NEW UI - ADD or EDIT, SEND EMAIL, NOTIFICATIONS $this->slugs['addedit'] = 'zbs-add-edit'; diff --git a/projects/plugins/crm/includes/ZeroBSCRM.CustomerFilters.php b/projects/plugins/crm/includes/ZeroBSCRM.CustomerFilters.php index 2d5932b37319..c7723069390b 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.CustomerFilters.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.CustomerFilters.php @@ -94,12 +94,12 @@ function zeroBSCRM_CompanyTypeList( $jsCallbackFuncStr = '', $inputDefaultValue // } Also need to make sure this is dumped out for js global $haszbscrmBHURLCompaniesOut; - if ( ! isset( $haszbscrmBHURLCompaniesOut ) ) { + if ( ! isset( $haszbscrmBHURLCompaniesOut ) ) { $nonce = wp_create_nonce( 'wp_rest' ); $rest_base_url = get_rest_url(); - // handle bare permalink structure + // handle bare permalink structure if ( empty( get_option( 'permalink_structure' ) ) ) { $param_separator = '&'; } else { @@ -109,7 +109,7 @@ function zeroBSCRM_CompanyTypeList( $jsCallbackFuncStr = '', $inputDefaultValue $ret .= ''; - $haszbscrmBHURLCompaniesOut = true; + $haszbscrmBHURLCompaniesOut = true; } // } Global JS does the rest ;) @@ -410,7 +410,7 @@ function zbs_customerFiltersRetrieveCustomers( $perPage = 10, $page = 1, $forceP // $zbsQPI['retrieveCustomers1'] = zeroBSCRM_mtime_float(); // } Req. - global $zbs,$zbsCustomerFields, $zbsCustomerFiltersInEffect, $zbsCustomerFiltersCurrentList; + global $zbs, $zbsCustomerFields, $zbsCustomerFiltersInEffect, $zbsCustomerFiltersCurrentList; // } Already cached? if ( diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL2.Mail.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL2.Mail.php index c11df84b0314..648bd85b5ce6 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL2.Mail.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL2.Mail.php @@ -328,7 +328,7 @@ function zeroBSCRM_mailTemplate_getMailDelMethod( $ID ) { // ... but when more free time, clean up this routine, bringing in all templates :) function zeroBSCRM_populateEmailTemplateList() { - global $wpdb,$ZBSCRM_t; // need to define this if using it below.. how did this slip through checks? + global $wpdb, $ZBSCRM_t; // need to define this if using it below.. how did this slip through checks? // IDs // 0 - the template itself.... can allow this to be edited.. or upsell it to be edited :/ $ID = 0; diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Fields.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Fields.php index 7f82c279446e..e1e4a046bc47 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Fields.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Fields.php @@ -22,13 +22,13 @@ / Breaking Checks ====================================================== */ - global $zbsFieldsEnabled,$zbsFieldSorts,$zbsAddressFields; + global $zbsFieldsEnabled, $zbsFieldSorts, $zbsAddressFields; $zbsFieldsEnabled = array(); // } ALSO added 'opt' field #} if this is set it'll be checked whether $zbsFieldsEnabled['optname'] global is true/false $zbsFieldSorts = array(); $zbsAddressFields = array(); // these are all DAL3 Object Loaded via zeroBSCRM_fields_initialise(): - global $zbsCustomerFields,$zbsCompanyFields,$zbsCustomerQuoteFields,$zbsCustomerInvoiceFields,$zbsTransactionFields,$zbsFormFields; + global $zbsCustomerFields, $zbsCompanyFields, $zbsCustomerQuoteFields, $zbsCustomerInvoiceFields, $zbsTransactionFields, $zbsFormFields; $zbsCustomerFields = array(); $zbsCompanyFields = array(); $zbsCustomerQuoteFields = array(); @@ -42,8 +42,8 @@ // This gets run in Core.php after initialising zbsDAL class function zeroBSCRM_fields_initialise() { - global $zbs,$zbsFieldsEnabled,$zbsFieldSorts,$zbsAddressFields; - global $zbsCustomerFields,$zbsCompanyFields,$zbsCustomerQuoteFields,$zbsCustomerInvoiceFields,$zbsTransactionFields,$zbsFormFields; + global $zbs, $zbsFieldsEnabled, $zbsFieldSorts, $zbsAddressFields; + global $zbsCustomerFields, $zbsCompanyFields, $zbsCustomerQuoteFields, $zbsCustomerInvoiceFields, $zbsTransactionFields, $zbsFormFields; /* ====================================================== @@ -397,7 +397,7 @@ function zeroBSCRM_unpackCustomFields() { // } Jammed for now, adds country if set! zeroBSCRM_internalAddressFieldMods(); - global $zbs,$zbsAddressFields,$zbsFieldSorts; + global $zbs, $zbsAddressFields, $zbsFieldSorts; $customfields = $zbs->settings->get( 'customfields' ); @@ -1289,7 +1289,7 @@ function zeroBSCRM_customFields_getSlugOrCreate( $fieldLabel = '', $objectTypeSt // block ID here too if ( ! empty( $fieldLabel ) && ! empty( $objectTypeStr ) && $fieldLabel != 'ID' && isset( $customFieldsToProcess[ $objectTypeStr ] ) ) { - global $wDB,$zbs; + global $wDB, $zbs; $customFieldsArr = $zbs->settings->get( 'customfields' ); @@ -1332,21 +1332,21 @@ function zeroBSCRM_customFields_getSlugOrCreate( $fieldLabel = '', $objectTypeSt // NOW SAVE DOWN - if ( isset( $customFieldsArr['customers'] ) && is_array( $customFieldsArr['customers'] ) ) { + if ( isset( $customFieldsArr['customers'] ) && is_array( $customFieldsArr['customers'] ) ) { - // slight array reconfig - $db2CustomFields = array(); - foreach ( $customFieldsArr['customers'] as $cfArr ) { - $db2CustomFields[ $zbs->DAL->makeSlug( $cfArr[1] ) ] = $cfArr; + // slight array reconfig + $db2CustomFields = array(); + foreach ( $customFieldsArr['customers'] as $cfArr ) { + $db2CustomFields[ $zbs->DAL->makeSlug( $cfArr[1] ) ] = $cfArr; } - // simple maintain DAL2 (needs to also) - $zbs->DAL->updateActiveCustomFields( - array( - 'objtypeid' => 1, - 'fields' => $db2CustomFields, - ) - ); + // simple maintain DAL2 (needs to also) + $zbs->DAL->updateActiveCustomFields( + array( + 'objtypeid' => 1, + 'fields' => $db2CustomFields, + ) + ); } // } Brutal update diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Addresses.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Addresses.php index f9061749bd06..8a9978cde07a 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Addresses.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Addresses.php @@ -1,5 +1,6 @@ -> Addresses -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Addresses + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_addresses extends zbsDAL_ObjectLayer { - - protected $objectType = ZBS_TYPE_ADDRESS; - //protected $objectDBPrefix = 'zbsadd_'; - protected $include_in_templating = true; - protected $objectModel = array( - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'addr1' => array( - // db model: - 'fieldname' => 'zbsa_addr1', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Address Line 1', - 'placeholder'=>'' - ), - 'addr2' => array( - // db model: - 'fieldname' => 'zbsa_addr2', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Address Line 2', - 'placeholder'=>'' - ), - 'city' => array( - // db model: - 'fieldname' => 'zbsa_city', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'City', - 'placeholder'=> 'e.g. New York' - ), - 'county' => array( - // db model: - 'fieldname' => 'zbsa_county', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'County', - 'placeholder'=> 'e.g. Kings County' - ), - 'postcode' => array( - // db model: - 'fieldname' => 'zbsa_postcode', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Post Code', - 'placeholder'=> 'e.g. 10019' - ), - 'country' => array( - // db model: - 'fieldname' => 'zbsa_country', 'format' => 'str', - // output model - 'input_type' => 'selectcountry', - 'label' => 'Country', - 'placeholder'=>'' - ), - - 'created' => array('fieldname' => 'zbsa_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsa_lastupdated', 'format' => 'uts'), - - ); - - - function __construct($args=array()) { - - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - - } - - - - // =============================================================================== - // =========== ADDRESS ======================================================== - - /* - - Addresses as distinct objects didn't make the v3.0 cut. - They'd be a valid area for expansion post v3.0. - - This file is here as a precursor, and is used by the 3.0 migration routine - to stop custom field keys colliding with field names (the obj model above) - (function zeroBSCRM_AJAX_dbMigration300open()) - - - */ - - // =========== / ADDRESS ===================================================== - // =============================================================================== + protected $objectType = ZBS_TYPE_ADDRESS; + // protected $objectDBPrefix = 'zbsadd_'; + protected $include_in_templating = true; + protected $objectModel = array( + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'addr1' => array( + // db model: + 'fieldname' => 'zbsa_addr1', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Address Line 1', + 'placeholder' => '', + ), + 'addr2' => array( + // db model: + 'fieldname' => 'zbsa_addr2', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Address Line 2', + 'placeholder' => '', + ), + 'city' => array( + // db model: + 'fieldname' => 'zbsa_city', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'City', + 'placeholder' => 'e.g. New York', + ), + 'county' => array( + // db model: + 'fieldname' => 'zbsa_county', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'County', + 'placeholder' => 'e.g. Kings County', + ), + 'postcode' => array( + // db model: + 'fieldname' => 'zbsa_postcode', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Post Code', + 'placeholder' => 'e.g. 10019', + ), + 'country' => array( + // db model: + 'fieldname' => 'zbsa_country', + 'format' => 'str', + // output model + 'input_type' => 'selectcountry', + 'label' => 'Country', + 'placeholder' => '', + ), + + 'created' => array( + 'fieldname' => 'zbsa_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsa_lastupdated', + 'format' => 'uts', + ), + + ); + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + } + + // =============================================================================== + // =========== ADDRESS ======================================================== + + /* + Addresses as distinct objects didn't make the v3.0 cut. + They'd be a valid area for expansion post v3.0. + + This file is here as a precursor, and is used by the 3.0 migration routine + to stop custom field keys colliding with field names (the obj model above) + (function zeroBSCRM_AJAX_dbMigration300open()) + + + */ + + // =========== / ADDRESS ===================================================== + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Companies.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Companies.php index 5dc2c31e0c08..22e728af9978 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Companies.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Companies.php @@ -1,5 +1,6 @@ -> Companies -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Companies + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_companies extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_COMPANY; - protected $objectDBPrefix = 'zbsco_'; - protected $objectIncludesAddresses = true; - protected $include_in_templating = true; - protected $objectModel = array( - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'status' => array( - // db model: + protected $objectType = ZBS_TYPE_COMPANY; + protected $objectDBPrefix = 'zbsco_'; + protected $objectIncludesAddresses = true; + protected $include_in_templating = true; + protected $objectModel = array( + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'status' => array( + // db model: 'fieldname' => 'zbsco_status', 'format' => 'str', - // output model - 'input_type' => 'select', - 'label' => 'Status', - 'placeholder'=>'', + // output model + 'input_type' => 'select', + 'label' => 'Status', + 'placeholder' => '', 'options' => array( 'Lead', 'Customer', 'Refused' ), - 'essential' => true, - 'max_len' => 50, - 'do_not_show_on_portal' => true - ), - 'name' => array( - // db model: - 'fieldname' => 'zbsco_name', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Name', - 'placeholder'=> 'e.g. NewCo', - 'dal1key' => 'coname', - 'essential' => true, - 'force_unique' => true, // must be unique. This is required and breaking if true, - 'not_empty' => true, - 'max_len' => 100 - ), - - - 'addr1' => array( - // db model: - 'fieldname' => 'zbsco_addr1', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Address Line 1', - 'placeholder'=>'', - 'area'=> 'Main Address', - 'migrate'=>'addresses', - 'max_len' => 200 - ), - 'addr2' => array( - // db model: - 'fieldname' => 'zbsco_addr2', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Address Line 2', - 'placeholder'=>'', - 'area'=> 'Main Address', - 'migrate'=>'addresses', - 'max_len' => 200 - ), - 'city' => array( - // db model: - 'fieldname' => 'zbsc_city', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'City', - 'placeholder'=> 'e.g. New York', - 'area'=> 'Main Address', - 'migrate'=>'addresses', + 'essential' => true, + 'max_len' => 50, + 'do_not_show_on_portal' => true, + ), + 'name' => array( + // db model: + 'fieldname' => 'zbsco_name', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Name', + 'placeholder' => 'e.g. NewCo', + 'dal1key' => 'coname', + 'essential' => true, + 'force_unique' => true, // must be unique. This is required and breaking if true, + 'not_empty' => true, + 'max_len' => 100, + ), + + 'addr1' => array( + // db model: + 'fieldname' => 'zbsco_addr1', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Address Line 1', + 'placeholder' => '', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 200, + ), + 'addr2' => array( + // db model: + 'fieldname' => 'zbsco_addr2', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Address Line 2', + 'placeholder' => '', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 200, + ), + 'city' => array( + // db model: + 'fieldname' => 'zbsc_city', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'City', + 'placeholder' => 'e.g. New York', + 'area' => 'Main Address', + 'migrate' => 'addresses', 'max_len' => 200, // phpcs:ignore Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed, WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned - ), - 'county' => array( - // db model: - 'fieldname' => 'zbsco_county', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'County', - 'placeholder'=> 'e.g. Kings County', - 'area'=> 'Main Address', - 'migrate'=>'addresses', - 'max_len' => 200 - ), - 'postcode' => array( - // db model: - 'fieldname' => 'zbsco_postcode', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Post Code', - 'placeholder'=> 'e.g. 10019', - 'area'=> 'Main Address', - 'migrate'=>'addresses', - 'max_len' => 50 - ), - 'country' => array( - // db model: - 'fieldname' => 'zbsco_country', 'format' => 'str', - // output model - 'input_type' => 'selectcountry', - 'label' => 'Country', - 'placeholder'=>'', - 'area'=> 'Main Address', - 'migrate'=>'addresses', - 'max_len' => 200 - ), - - - 'secaddr1' => array( - // db model: - 'fieldname' => 'zbsco_secaddr1', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Address Line 1', - 'placeholder'=>'', - 'area'=> 'Second Address', - 'migrate'=>'addresses', - 'opt'=>'secondaddress', - 'max_len' => 200, - 'dal1key' => 'secaddr_addr1' // previous field name - ), - 'secaddr2' => array( - // db model: - 'fieldname' => 'zbsco_secaddr2', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Address Line 2', - 'placeholder'=>'', - 'area'=> 'Second Address', - 'migrate'=>'addresses', - 'opt'=>'secondaddress', - 'max_len' => 200, - 'dal1key' => 'secaddr_addr2' // previous field name - ), - 'seccity' => array( - // db model: - 'fieldname' => 'zbsco_seccity', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'City', - 'placeholder'=> 'e.g. Los Angeles', - 'area'=> 'Second Address', - 'migrate'=>'addresses', - 'opt'=>'secondaddress', + ), + 'county' => array( + // db model: + 'fieldname' => 'zbsco_county', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'County', + 'placeholder' => 'e.g. Kings County', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 200, + ), + 'postcode' => array( + // db model: + 'fieldname' => 'zbsco_postcode', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Post Code', + 'placeholder' => 'e.g. 10019', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 50, + ), + 'country' => array( + // db model: + 'fieldname' => 'zbsco_country', + 'format' => 'str', + // output model + 'input_type' => 'selectcountry', + 'label' => 'Country', + 'placeholder' => '', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 200, + ), + + 'secaddr1' => array( + // db model: + 'fieldname' => 'zbsco_secaddr1', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Address Line 1', + 'placeholder' => '', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 200, + 'dal1key' => 'secaddr_addr1', // previous field name + ), + 'secaddr2' => array( + // db model: + 'fieldname' => 'zbsco_secaddr2', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Address Line 2', + 'placeholder' => '', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 200, + 'dal1key' => 'secaddr_addr2', // previous field name + ), + 'seccity' => array( + // db model: + 'fieldname' => 'zbsco_seccity', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'City', + 'placeholder' => 'e.g. Los Angeles', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', 'max_len' => 200, // phpcs:ignore Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed, WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned - 'dal1key' => 'secaddr_city' // previous field name - ), - 'seccounty' => array( - // db model: - 'fieldname' => 'zbsco_seccounty', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'County', - 'placeholder'=> 'e.g. Los Angeles', - 'area'=> 'Second Address', - 'migrate'=>'addresses', - 'opt'=>'secondaddress', - 'max_len' => 200, - 'dal1key' => 'secaddr_county' // previous field name - ), - 'secpostcode' => array( - // db model: - 'fieldname' => 'zbsco_secpostcode', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Post Code', - 'placeholder'=> 'e.g. 90001', - 'area'=> 'Second Address', - 'migrate'=>'addresses', - 'opt'=>'secondaddress', - 'max_len' => 50, - 'dal1key' => 'secaddr_postcode' // previous field name - ), - 'seccountry' => array( - // db model: - 'fieldname' => 'zbsco_seccountry', 'format' => 'str', - // output model - 'input_type' => 'selectcountry', - 'label' => 'Country', - 'placeholder'=>'', - 'area'=> 'Second Address', - 'migrate'=>'addresses', - 'opt'=>'secondaddress', - 'max_len' => 200, - 'dal1key' => 'secaddr_country' // previous field name - ), - - 'maintel' => array( - // db model: - 'fieldname' => 'zbsco_maintel', 'format' => 'str', - // output model - 'input_type' => 'tel', - 'label' => 'Main Telephone', - 'placeholder'=> 'e.g. 877 2733049', - 'max_len' => 40 - ), - 'sectel' => array( - // db model: - 'fieldname' => 'zbsco_sectel', 'format' => 'str', - // output model - 'input_type' => 'tel', - 'label' => 'Secondary Telephone', - 'placeholder'=> 'e.g. 877 2733049', - 'max_len' => 40 - ), - 'email' => array( - // db model: - 'fieldname' => 'zbsco_email', 'format' => 'str', - // output model - 'input_type' => 'email', - 'label' => 'Main Email Address', - 'placeholder'=> 'e.g. hello@company.com', - 'max_len' => 200, - 'force_unique' => true, // must be unique. This is required and breaking if true - 'can_be_blank' => true, - 'do_not_show_on_portal' => true - ), - - // ... just removed for DAL3 :) should be custom field anyway by this point - - 'wpid' => array('fieldname' => 'zbsco_wpid', 'format' => 'int'), - 'avatar' => array('fieldname' => 'zbsco_avatar', 'format' => 'str'), - 'tw' => array( - 'fieldname' => 'zbsco_tw', - 'format' => 'str', - 'max_len' => 100 - ), - 'li' => array( - 'fieldname' => 'zbsco_li', - 'format' => 'str', - 'max_len' => 300 - ), - 'fb' => array( - 'fieldname' => 'zbsco_fb', - 'format' => 'str', - 'max_len' => 200 - ), - 'created' => array('fieldname' => 'zbsco_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsco_lastupdated', 'format' => 'uts'), - 'lastcontacted' => array('fieldname' => 'zbsco_lastcontacted', 'format' => 'uts'), - - ); - - - function __construct($args=array()) { - - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + 'dal1key' => 'secaddr_city', // previous field name + ), + 'seccounty' => array( + // db model: + 'fieldname' => 'zbsco_seccounty', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'County', + 'placeholder' => 'e.g. Los Angeles', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 200, + 'dal1key' => 'secaddr_county', // previous field name + ), + 'secpostcode' => array( + // db model: + 'fieldname' => 'zbsco_secpostcode', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Post Code', + 'placeholder' => 'e.g. 90001', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 50, + 'dal1key' => 'secaddr_postcode', // previous field name + ), + 'seccountry' => array( + // db model: + 'fieldname' => 'zbsco_seccountry', + 'format' => 'str', + // output model + 'input_type' => 'selectcountry', + 'label' => 'Country', + 'placeholder' => '', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 200, + 'dal1key' => 'secaddr_country', // previous field name + ), + + 'maintel' => array( + // db model: + 'fieldname' => 'zbsco_maintel', + 'format' => 'str', + // output model + 'input_type' => 'tel', + 'label' => 'Main Telephone', + 'placeholder' => 'e.g. 877 2733049', + 'max_len' => 40, + ), + 'sectel' => array( + // db model: + 'fieldname' => 'zbsco_sectel', + 'format' => 'str', + // output model + 'input_type' => 'tel', + 'label' => 'Secondary Telephone', + 'placeholder' => 'e.g. 877 2733049', + 'max_len' => 40, + ), + 'email' => array( + // db model: + 'fieldname' => 'zbsco_email', + 'format' => 'str', + // output model + 'input_type' => 'email', + 'label' => 'Main Email Address', + 'placeholder' => 'e.g. hello@company.com', + 'max_len' => 200, + 'force_unique' => true, // must be unique. This is required and breaking if true + 'can_be_blank' => true, + 'do_not_show_on_portal' => true, + ), + + // ... just removed for DAL3 :) should be custom field anyway by this point + + 'wpid' => array( + 'fieldname' => 'zbsco_wpid', + 'format' => 'int', + ), + 'avatar' => array( + 'fieldname' => 'zbsco_avatar', + 'format' => 'str', + ), + 'tw' => array( + 'fieldname' => 'zbsco_tw', + 'format' => 'str', + 'max_len' => 100, + ), + 'li' => array( + 'fieldname' => 'zbsco_li', + 'format' => 'str', + 'max_len' => 300, + ), + 'fb' => array( + 'fieldname' => 'zbsco_fb', + 'format' => 'str', + 'max_len' => 200, + ), + 'created' => array( + 'fieldname' => 'zbsco_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsco_lastupdated', + 'format' => 'uts', + ), + 'lastcontacted' => array( + 'fieldname' => 'zbsco_lastcontacted', + 'format' => 'uts', + ), + + ); + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= add_filter( 'jpcrm_listview_filters', array( $this, 'add_listview_filters' ) ); - - } + } /** * Adds items to listview filter using `jpcrm_listview_filters` hook. @@ -324,51 +377,53 @@ public function add_listview_filters( $listview_filters ) { return $listview_filters; } - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ - - return $this->getCompany($ID); - - } + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { - // generic get contact (by ID list) - // Super simplistic wrapper used by MVP Export v3.0 - public function getIDList($IDs=false){ - - return $this->getCompanies(array( - 'inArr' => $IDs, - 'withCustomFields' => true, - 'page' => -1, - 'perPage' => -1 - )); - - } - - // generic get (EVERYTHING) - // expect heavy load! - public function getAll($IDs=false){ + return $this->getCompany( $ID ); + } - return $this->getCompanies(array( - 'withCustomFields' => true, - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => -1, - 'perPage' => -1, - )); + // generic get contact (by ID list) + // Super simplistic wrapper used by MVP Export v3.0 + public function getIDList( $IDs = false ) { + + return $this->getCompanies( + array( + 'inArr' => $IDs, + 'withCustomFields' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } - } - - // generic get count of (EVERYTHING) - public function getFullCount(){ + // generic get (EVERYTHING) + // expect heavy load! + public function getAll( $IDs = false ) { + + return $this->getCompanies( + array( + 'withCustomFields' => true, + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => -1, + 'perPage' => -1, + ) + ); + } - return $this->getCompanies(array( - 'count' => true, - 'page' => -1, - 'perPage' => -1, - )); + // generic get count of (EVERYTHING) + public function getFullCount() { - } + return $this->getCompanies( + array( + 'count' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } /** * Retrieves the company ID by its name. @@ -397,882 +452,951 @@ public function get_company_id_by_name( $name ) { return false; } - /** - * returns full company line +- details - * - * @param int id company id - * @param array $args Associative array of arguments - * - * @return array company object - */ - public function getCompany($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - 'email' => false, // if id -1 and email given, will return based on email - 'name' => false, // if id -1 and name given, will return based on name - - // if theset wo passed, will search based on these - 'externalSource' => false, - 'externalSourceUID' => false, - - // with what? - 'withCustomFields' => true, - 'withQuotes' => false, - 'withInvoices' => false, - 'withTransactions' => false, - 'withTasks' => false, - //'withLogs' => false, - 'withLastLog' => false, - 'withTags' => false, - 'withOwner' => false, - 'withValues' => false, // if passed, returns with 'total' 'invoices_total' 'transactions_total' etc. (requires getting all obj, use sparingly) - 'withContacts' => true, // return ['contact'] objs - 'withExternalSources' => false, - 'withExternalSourcesGrouped' => false, - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY), // this'll let you not-check the owner of obj - - // returns scalar ID of line - 'onlyID' => false, - - 'fields' => false // false = *, array = fieldnames - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check ID - $id = (int)$id; - if ( - (!empty($id) && $id > 0) - || - (!empty($email)) + /** + * returns full company line +- details + * + * @param int id company id + * @param array $args Associative array of arguments + * + * @return array company object + */ + public function getCompany( $id = -1, $args = array() ) { + + global $zbs; + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + 'email' => false, // if id -1 and email given, will return based on email + 'name' => false, // if id -1 and name given, will return based on name + + // if theset wo passed, will search based on these + 'externalSource' => false, + 'externalSourceUID' => false, + + // with what? + 'withCustomFields' => true, + 'withQuotes' => false, + 'withInvoices' => false, + 'withTransactions' => false, + 'withTasks' => false, + // 'withLogs' => false, + 'withLastLog' => false, + 'withTags' => false, + 'withOwner' => false, + 'withValues' => false, // if passed, returns with 'total' 'invoices_total' 'transactions_total' etc. (requires getting all obj, use sparingly) + 'withContacts' => true, // return ['contact'] objs + 'withExternalSources' => false, + 'withExternalSourcesGrouped' => false, + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + 'fields' => false, // false = *, array = fieldnames + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + #} Check ID + $id = (int) $id; + if ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $email ) ) || ( ! empty( $name ) ) - || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ + || + ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) + ) { - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $extraSelect = ''; + #} ============= PRE-QUERY ============ - #} ============= PRE-QUERY ============ + #} Custom Fields + if ( $withCustomFields && ! $onlyID ) { - #} Custom Fields - if ($withCustomFields && !$onlyID){ - - #} Retrieve any cf - $custFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_COMPANY)); + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_COMPANY ) ); - #} Cycle through + build into query - if (is_array($custFields)) foreach ($custFields as $cK => $cF){ + #} Cycle through + build into query + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '".$cK."'"; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_COMPANY; + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . " WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '" . $cK . "'"; - } + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_COMPANY; - } + } + } + } - // Add any addr custom fields for addr1+addr2 - $addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); - if ($withCustomFields && !$onlyID && is_array($addrCustomFields) && count($addrCustomFields) > 0){ + // Add any addr custom fields for addr1+addr2 + $addrCustomFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); + if ( $withCustomFields && ! $onlyID && is_array( $addrCustomFields ) && count( $addrCustomFields ) > 0 ) { + + foreach ( $addrCustomFields as $cK => $cF ) { + + // custom field key + $cfKey = 'addr_' . $cK; + $cfKey2 = 'secaddr_' . $cK; + + // address custom field (e.g. 'house name') it'll be passed here as 'house-name' + // ... problem is mysql does not like that :) so we have to chage here: + // in this case we prepend address cf's with addr_ and we switch - for _ + $cKey = 'addrcf_' . str_replace( '-', '_', $cK ); + $cKey2 = 'secaddrcf_' . str_replace( '-', '_', $cK ); + + // addr1 + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey; + // add params + $params[] = $cfKey; + $params[] = ZBS_TYPE_COMPANY; + // addr2 + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey2; + // add params + $params[] = $cfKey2; + $params[] = ZBS_TYPE_COMPANY; + + } + } - foreach ($addrCustomFields as $cK => $cF){ + // ==== TOTAL VALUES - // custom field key - $cfKey = 'addr_'.$cK; - $cfKey2 = 'secaddr_'.$cK; + // Calculate total vals etc. with SQL + if ( ! $onlyID && $withValues ) { - // address custom field (e.g. 'house name') it'll be passed here as 'house-name' - // ... problem is mysql does not like that :) so we have to chage here: - // in this case we prepend address cf's with addr_ and we switch - for _ - $cKey = 'addrcf_'.str_replace('-','_',$cK); - $cKey2 = 'secaddrcf_'.str_replace('-','_',$cK); + // arguably, if getting $withInvoices etc. may be more performant to calc this in php in AFTER loop, + // ... for now as a fair guess, this'll be most performant: + // ... we calc total by adding invs + trans below :) - // addr1 - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey; - // add params - $params[] = $cfKey; $params[] = ZBS_TYPE_COMPANY; - // addr2 - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey2; - // add params - $params[] = $cfKey2; $params[] = ZBS_TYPE_COMPANY; + // only include transactions with statuses which should be included in total value: + $transStatusQueryAdd = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); + // include invoices without deleted status in the total value for invoices_total_inc_deleted: + $inv_status_query_add = $this->DAL()->invoices->get_invoice_status_except_deleted_for_query(); - } + // quotes: + $extraSelect .= ',(SELECT SUM(quotestotal.zbsq_value) FROM ' . $ZBSCRM_t['quotes'] . ' as quotestotal WHERE quotestotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_QUOTE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as quotes_total'; + // invs: + $extraSelect .= ',(SELECT IFNULL(SUM(invstotal.zbsi_total),0) FROM ' . $ZBSCRM_t['invoices'] . ' as invstotal WHERE invstotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ') as invoices_total'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // invs including deleted: + $extraSelect .= ',(SELECT SUM(invstotalincdeleted.zbsi_total) FROM ' . $ZBSCRM_t['invoices'] . ' as invstotalincdeleted WHERE invstotalincdeleted.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as invoices_total_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // invs count: + $extraSelect .= ',(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ') as invoices_count'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // invs count including deleted: + $extraSelect .= ',(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as invoices_count_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // trans (with status): + $extraSelect .= ',(SELECT SUM(transtotal.zbst_total) FROM ' . $ZBSCRM_t['transactions'] . ' as transtotal WHERE transtotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $transStatusQueryAdd . ') as transactions_total'; + // paid balance against invs (also in getCompany) + // (this allows us to subtract from totals to get a true figure where transactions are part/whole payments for invs) + /* + This selects transactions + where there is a link to an invoice + where that invoice has a link to this contact: + ========== - } + SELECT * FROM wp_zbs_transactions trans + WHERE trans.ID IN + ( + SELECT DISTINCT zbsol_objid_from FROM `wp_zbs_object_links` + WHERE zbsol_objtype_from = 5 + AND zbsol_objtype_to = 4 + AND zbsol_objid_to IN - + ( + SELECT DISTINCT zbsol_objid_from FROM `wp_zbs_object_links` + WHERE zbsol_objtype_from = 4 AND zbsol_objtype_to = 1 AND zbsol_objid_to = 1 + ) + ) - // ==== TOTAL VALUES - // Calculate total vals etc. with SQL - if (!$onlyID && $withValues){ + */ + $extraSelect .= ',(SELECT SUM(assignedtranstotal.zbst_total) FROM ' . $ZBSCRM_t['transactions'] . ' assignedtranstotal WHERE assignedtranstotal.ID IN '; + $extraSelect .= '(SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objid_to IN '; + $extraSelect .= '(SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)'; + $extraSelect .= ')' . $transStatusQueryAdd . ') as transactions_paid_total'; + } - // arguably, if getting $withInvoices etc. may be more performant to calc this in php in AFTER loop, - // ... for now as a fair guess, this'll be most performant: - // ... we calc total by adding invs + trans below :) + // ==== / TOTAL VALUES - // only include transactions with statuses which should be included in total value: - $transStatusQueryAdd = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); - // include invoices without deleted status in the total value for invoices_total_inc_deleted: - $inv_status_query_add = $this->DAL()->invoices->get_invoice_status_except_deleted_for_query(); + $selector = 'company.*'; + if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $selector = ''; + + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'company.ID'; + } + + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'company.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'company.ID'; + } - // quotes: - $extraSelect .= ',(SELECT SUM(quotestotal.zbsq_value) FROM '.$ZBSCRM_t['quotes'].' as quotestotal WHERE quotestotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_QUOTE." AND zbsol_objtype_to = ".ZBS_TYPE_COMPANY." AND zbsol_objid_to = company.ID)) as quotes_total"; - // invs: - $extraSelect .= ',(SELECT IFNULL(SUM(invstotal.zbsi_total),0) FROM ' . $ZBSCRM_t['invoices'] . ' as invstotal WHERE invstotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ') as invoices_total'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // invs including deleted: - $extraSelect .= ',(SELECT SUM(invstotalincdeleted.zbsi_total) FROM ' . $ZBSCRM_t['invoices'] . ' as invstotalincdeleted WHERE invstotalincdeleted.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as invoices_total_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // invs count: - $extraSelect .= ',(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ') as invoices_count'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // invs count including deleted: - $extraSelect .= ',(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as invoices_count_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // trans (with status): - $extraSelect .= ',(SELECT SUM(transtotal.zbst_total) FROM '.$ZBSCRM_t['transactions'].' as transtotal WHERE transtotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_TRANSACTION." AND zbsol_objtype_to = ".ZBS_TYPE_COMPANY." AND zbsol_objid_to = company.ID)".$transStatusQueryAdd.") as transactions_total"; - // paid balance against invs (also in getCompany) - // (this allows us to subtract from totals to get a true figure where transactions are part/whole payments for invs) - /* + #} ============ / PRE-QUERY =========== - This selects transactions - where there is a link to an invoice - where that invoice has a link to this contact: + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['companies'] . ' as company'; + #} ============= WHERE ================ - ========== + if ( ! empty( $id ) && $id > 0 ) { - SELECT * FROM wp_zbs_transactions trans - WHERE trans.ID IN - - ( - SELECT DISTINCT zbsol_objid_from FROM `wp_zbs_object_links` - WHERE zbsol_objtype_from = 5 - AND zbsol_objtype_to = 4 - AND zbsol_objid_to IN + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - ( + } - SELECT DISTINCT zbsol_objid_from FROM `wp_zbs_object_links` - WHERE zbsol_objtype_from = 4 AND zbsol_objtype_to = 1 AND zbsol_objid_to = 1 + if ( ! empty( $email ) ) { - ) + $emailWheres = array(); - ) + // simple, inc AKA (even tho not in UI yet :)) + // nope$wheres['emailcheck'] = array('zbsco_email','=','%s',$email); + #} Add ID + $emailWheres['emailcheck'] = array( 'zbsco_email', '=', '%s', $email ); - */ - $extraSelect .= ',(SELECT SUM(assignedtranstotal.zbst_total) FROM '.$ZBSCRM_t['transactions'].' assignedtranstotal WHERE assignedtranstotal.ID IN '; - $extraSelect .= '(SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_TRANSACTION.' AND zbsol_objtype_to = '.ZBS_TYPE_INVOICE.' AND zbsol_objid_to IN '; - $extraSelect .= '(SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_INVOICE.' AND zbsol_objtype_to = '.ZBS_TYPE_COMPANY.' AND zbsol_objid_to = company.ID)'; - $extraSelect .= ')'.$transStatusQueryAdd.') as transactions_paid_total'; - } + #} Check AKA + $emailWheres['email_alias'] = array( 'ID', 'IN', '(SELECT aka_id FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_COMPANY . ' AND aka_alias = %s)', $email ); - // ==== / TOTAL VALUES + // This generates a query like 'zbsc_email = %s OR zbsc_email2 = %s', + // which we then need to include as direct subquery (below) in main query :) + $emailSearchQueryArr = $this->buildWheres( $emailWheres, '', array(), 'OR', false ); - $selector = 'company.*'; - if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $selector = ''; + if ( is_array( $emailSearchQueryArr ) && isset( $emailSearchQueryArr['where'] ) && ! empty( $emailSearchQueryArr['where'] ) ) { - // always needs id, so add if not present - if (!in_array('ID',$fields)) $selector = 'company.ID'; + // add it + $wheres['direct'][] = array( '(' . $emailSearchQueryArr['where'] . ')', $emailSearchQueryArr['params'] ); - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'company.'.$f; - } - } else if ($onlyID){ - $selector = 'company.ID'; - } + } + } - #} ============ / PRE-QUERY =========== + if ( ! empty( $name ) ) { + // simple + $wheres['name'] = array( 'zbsco_name', '=', '%s', $name ); - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['companies'].' as company'; - #} ============= WHERE ================ + } - if (!empty($id) && $id > 0){ + if ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) { - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); + $wheres['extsourcecheck'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_COMPANY . ' AND zbss_source = %s AND zbss_uid = %s)', array( $externalSource, $externalSourceUID ) ); - } + } - if (!empty($email)){ + #} ============ / WHERE ============== - $emailWheres = array(); + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - // simple, inc AKA (even tho not in UI yet :)) - //nope$wheres['emailcheck'] = array('zbsco_email','=','%s',$email); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Add ID - $emailWheres['emailcheck'] = array('zbsco_email','=','%s',$email); + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - #} Check AKA - $emailWheres['email_alias'] = array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_COMPANY." AND aka_alias = %s)",$email); - - // This generates a query like 'zbsc_email = %s OR zbsc_email2 = %s', - // which we then need to include as direct subquery (below) in main query :) - $emailSearchQueryArr = $this->buildWheres($emailWheres,'',array(),'OR',false); - - if (is_array($emailSearchQueryArr) && isset($emailSearchQueryArr['where']) && !empty($emailSearchQueryArr['where'])){ + try { - // add it - $wheres['direct'][] = array('('.$emailSearchQueryArr['where'].')',$emailSearchQueryArr['params']); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - } - + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - if (!empty($name)){ + } - // simple - $wheres['name'] = array('zbsco_name','=','%s',$name); + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - } - - if (!empty($externalSource) && !empty($externalSourceUID)){ + #} Has results, tidy + return - $wheres['extsourcecheck'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_COMPANY." AND zbss_source = %s AND zbss_uid = %s)",array($externalSource,$externalSourceUID)); + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } - } + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_company( $potentialRes, $withCustomFields ); + } - #} ============ / WHERE ============== + // TWO methods here, this feels more "common sense" (other commented out below.) + if ( $withInvoices ) { - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} only gets first 100? + // DAL3 ver, more perf, gets all + $res['invoices'] = $zbs->DAL->invoices->getInvoices( + array( - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + 'assignedCompany' => $potentialRes->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + ) + ); - try { + } - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + if ( $withQuotes ) { - } catch (Exception $e){ + // DAL3 ver, more perf, gets all + $res['quotes'] = $zbs->DAL->quotes->getQuotes( + array( - #} General SQL Err - $this->catchSQLError($e); + 'assignedCompany' => $potentialRes->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), - } + ) + ); - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + } - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID) return $potentialRes->ID; - - // tidy - if (is_array($fields)){ - // guesses fields based on table col names - $res = $this->lazyTidyGeneric($potentialRes); - } else { - // proper tidy - $res = $this->tidy_company($potentialRes,$withCustomFields); - } + #} ... brutal for mvp #DB1LEGACY (TOMOVE) + if ( $withTransactions ) { - // TWO methods here, this feels more "common sense" (other commented out below.) - if ($withInvoices){ - - #} only gets first 100? - //DAL3 ver, more perf, gets all - $res['invoices'] = $zbs->DAL->invoices->getInvoices(array( + // DAL3 ver, more perf, gets all + $res['transactions'] = $zbs->DAL->transactions->getTransactions( + array( - 'assignedCompany' => $potentialRes->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE) + 'assignedCompany' => $potentialRes->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), - )); + ) + ); - } + } + /* + #} With quotes? + if ($withQuotes){ - if ($withQuotes){ - - //DAL3 ver, more perf, gets all - $res['quotes'] = $zbs->DAL->quotes->getQuotes(array( + // add all quotes lines + $res['quotes'] = $this->DAL()->getObjsLinkedToObj(array( + 'objtypefrom' => ZBS_TYPE_QUOTE, // quote + 'objtypeto' => ZBS_TYPE_COMPANY, // company + 'objfromid' => $potentialRes->ID)); - 'assignedCompany' => $potentialRes->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE) + } - )); + #} With invoices? + if ($withQuotes){ - } + // add all invoices lines + $res['invoices'] = $this->DAL()->getObjsLinkedToObj(array( + 'objtypefrom' => ZBS_TYPE_INVOICE, // invoice + 'objtypeto' => ZBS_TYPE_COMPANY, // company + 'objfromid' => $potentialRes->ID)); - #} ... brutal for mvp #DB1LEGACY (TOMOVE) - if ($withTransactions){ - - //DAL3 ver, more perf, gets all - $res['transactions'] = $zbs->DAL->transactions->getTransactions(array( + } - 'assignedCompany' => $potentialRes->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION) + #} With transactions? + if ($withTransactions){ - )); + // add all transactions lines + $res['transactions'] = $this->DAL()->getObjsLinkedToObj(array( + 'objtypefrom' => ZBS_TYPE_TRANSACTION, // transaction + 'objtypeto' => ZBS_TYPE_COMPANY, // company + 'objfromid' => $potentialRes->ID)); - } - /* + } */ - #} With quotes? - if ($withQuotes){ + #} With most recent log? #DB1LEGACY (TOMOVE) + if ( $withLastLog ) { - // add all quotes lines - $res['quotes'] = $this->DAL()->getObjsLinkedToObj(array( - 'objtypefrom' => ZBS_TYPE_QUOTE, // quote - 'objtypeto' => ZBS_TYPE_COMPANY, // company - 'objfromid' => $potentialRes->ID)); - - } - - #} With invoices? - if ($withQuotes){ - - // add all invoices lines - $res['invoices'] = $this->DAL()->getObjsLinkedToObj(array( - 'objtypefrom' => ZBS_TYPE_INVOICE, // invoice - 'objtypeto' => ZBS_TYPE_COMPANY, // company - 'objfromid' => $potentialRes->ID)); - - } + $res['lastlog'] = $this->DAL()->logs->getLogsForObj( + array( - #} With transactions? - if ($withTransactions){ + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $potentialRes->ID, - // add all transactions lines - $res['transactions'] = $this->DAL()->getObjsLinkedToObj(array( - 'objtypefrom' => ZBS_TYPE_TRANSACTION, // transaction - 'objtypeto' => ZBS_TYPE_COMPANY, // company - 'objfromid' => $potentialRes->ID)); - - } */ + 'incMeta' => true, - #} With most recent log? #DB1LEGACY (TOMOVE) - if ($withLastLog){ + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, - $res['lastlog'] = $this->DAL()->logs->getLogsForObj(array( - - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $potentialRes->ID, - - 'incMeta' => true, + ) + ); - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1 + } - )); + if ( $withContacts ) { - } + // add all assigned contacts/companies + $res['contacts'] = $this->DAL()->contacts->getContacts( + array( + 'isLinkedToObjType' => ZBS_TYPE_COMPANY, + 'isLinkedToObjID' => $potentialRes->ID, + 'page' => -1, + 'perPage' => 100, // commonsense cap + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); - if ($withContacts){ + } - // add all assigned contacts/companies - $res['contacts'] = $this->DAL()->contacts->getContacts(array( - 'isLinkedToObjType'=>ZBS_TYPE_COMPANY, - 'isLinkedToObjID'=>$potentialRes->ID, - 'page'=>-1, - 'perPage'=>100, // commonsense cap - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + if ( $withTags ) { - } + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_COMPANY, + 'objid' => $potentialRes->ID, + ) + ); - if ($withTags){ + } - // add all tags lines - $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_COMPANY,'objid'=>$potentialRes->ID)); - - } - - #} With Assigned? - if ($withOwner){ - - $res['owner'] = zeroBS_getOwner($potentialRes->ID,true,'zerobs_company',$potentialRes->zbs_owner); - - } - - #} With Tasks? - if ($withTasks){ - - //DAL3 ver, more perf, gets all - $res['tasks'] = $zbs->DAL->events->getEvents(array( - - 'assignedCompany' => $potentialRes->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK), - 'sortByField' => 'zbse_start', - 'sortOrder' => 'DESC', - 'withAssigned' => false // no need, it's assigned to this obj already - - )); - - } - - // simplistic, could be optimised (though low use means later.) - if ( $withExternalSources ){ - - $res['external_sources'] = $zbs->DAL->getExternalSources( array( - - 'objectID' => $potentialRes->ID, - 'objectType' => ZBS_TYPE_COMPANY, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ) - - )); - - } - if ( $withExternalSourcesGrouped ){ - - $res['external_sources'] = $zbs->DAL->getExternalSources( -1, array( - - 'objectID' => $potentialRes->ID, - 'objectType' => ZBS_TYPE_COMPANY, - 'grouped_by_source' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ) - - )); - - } - - - return $res; - - } - - } // / if ID - - return false; - - } - - /** - * returns company detail lines - * - * @param array $args Associative array of arguments - * - * @return array of company lines - */ - public function getCompanies($args=array()){ - - global $zbs; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches which fields? - 'inArr' => false, - 'isTagged' => false, // 1x INT OR array(1,2,3) - 'isNotTagged' => false, // 1x INT OR array(1,2,3) - 'ownedBy' => false, - 'externalSource' => false, // e.g. paypal - 'olderThan' => false, // uts - 'newerThan' => false, // uts - 'hasStatus' => false, // Lead (this takes over from the quick filter post 19/6/18) - 'otherStatus' => false, // status other than 'Lead' - 'hasContact' => false, // has a contact of this ID associated with it - 'quickFilters' => false, // booo - - // addr - 'inCounty' => false, // Hertfordshire - 'inPostCode' => false, // AL1 1AA - 'inCountry' => false, // United Kingdom - 'notInCounty' => false, // Hertfordshire - 'notInPostCode' => false, // AL1 1AA - 'notInCountry' => false, // United Kingdom - - // generic assignments - requires both - // Where the link relationship is OBJECT -> CONTACT - 'hasObjIDLinkedTo' => false, // e.g. quoteid 123 - 'hasObjTypeLinkedTo' => false, // e.g. ZBS_TYPE_QUOTE - - // generic assignments - requires both - // Where the link relationship is CONTACT -> OBJECT - 'isLinkedToObjID' => false, // e.g. quoteid 123 - 'isLinkedToObjType' => false, // e.g. ZBS_TYPE_QUOTE - - // returns - 'count' => false, - 'withCustomFields' => true, - 'withQuotes' => false, // Will only be operable when Company<->Quotes established - 'withInvoices' => false, - 'withTransactions' => false, - 'withTasks' => false, - 'withTags' => false, - 'withOwner' => false, - 'withLogs' => false, - 'withLastLog' => false, - 'withValues' => false, // if passed, returns with 'total' 'invoices_total' 'transactions_total' etc. (requires getting all obj, use sparingly) - 'withContacts' => true, // return ['contact'] objs - 'withExternalSources' => false, - 'withExternalSourcesGrouped' => false, - 'simplified' => false, // returns just id,name,created (for typeaheads) - 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) - - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 100, - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY), // this'll let you not-check the owner of obj + #} With Assigned? + if ( $withOwner ) { + $res['owner'] = zeroBS_getOwner( $potentialRes->ID, true, 'zerobs_company', $potentialRes->zbs_owner ); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - global $ZBSCRM_t,$wpdb,$zbs; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; $whereCase = 'AND'; - - #} ============= PRE-QUERY ============ + } - #} Capitalise this - $sortOrder = strtoupper($sortOrder); + #} With Tasks? + if ( $withTasks ) { - #} If just count, or simplified, turn off any extra gumpf - if ( $count || $simplified ) { - $withCustomFields = false; - $withTags = false; - $withOwner = false; - $withLogs = false; - $withLastLog = false; - $withContacts = false; - $withTasks = false; - $withExternalSources = false; - $withExternalSourcesGrouped = false; - } - - #} If onlyColumns, validate - if ($onlyColumns){ - - #} onlyColumns build out a field arr - if (is_array($onlyColumns) && count($onlyColumns) > 0){ - - $onlyColumnsFieldArr = array(); - foreach ($onlyColumns as $col){ - - // find db col key from field key (e.g. fname => zbsc_fname) - $dbCol = ''; if (isset($this->objectModel[$col]) && isset($this->objectModel[$col]['fieldname'])) $dbCol = $this->objectModel[$col]['fieldname']; - - if (!empty($dbCol)){ - - $onlyColumnsFieldArr[$dbCol] = $col; - - } - - } - - } - - // if legit cols: - if (isset($onlyColumnsFieldArr) && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ - - $onlyColumns = true; - - // If onlyColumns, turn off extras - $withCustomFields = false; - $withTags = false; - $withOwner = false; - $withLogs = false; - $withLastLog = false; - $withContacts = false; - $withTasks = false; - $withExternalSources = false; - $withExternalSourcesGrouped = false; + // DAL3 ver, more perf, gets all + $res['tasks'] = $zbs->DAL->events->getEvents( + array( - } else { + 'assignedCompany' => $potentialRes->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), + 'sortByField' => 'zbse_start', + 'sortOrder' => 'DESC', + 'withAssigned' => false, // no need, it's assigned to this obj already - // deny - $onlyColumns = false; + ) + ); - } + } + // simplistic, could be optimised (though low use means later.) + if ( $withExternalSources ) { - } + $res['external_sources'] = $zbs->DAL->getExternalSources( + array( - #} Custom Fields - // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. - if ($withCustomFields){ - - #} Retrieve any cf - $custFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_COMPANY)); + 'objectID' => $potentialRes->ID, + 'objectType' => ZBS_TYPE_COMPANY, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), - #} Cycle through + build into query - if (is_array($custFields)) foreach ($custFields as $cK => $cF){ + ) + ); - // custom field (e.g. 'third name') it'll be passed here as 'third-name' - // ... problem is mysql does not like that :) so we have to chage here: - // in this case we prepend cf's with cf_ and we switch - for _ - $cKey = 'cf_'.str_replace('-','_',$cK); + } + if ( $withExternalSourcesGrouped ) { - // we also check the $sortByField in case that's the same cf - if ($cK == $sortByField){ + $res['external_sources'] = $zbs->DAL->getExternalSources( + -1, + array( - // sort by - $sortByField = $cKey; + 'objectID' => $potentialRes->ID, + 'objectType' => ZBS_TYPE_COMPANY, + 'grouped_by_source' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), - // check if sort needs any CAST (e.g. numeric): - $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); + ) + ); - } + } - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ".$cKey; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_COMPANY; + return $res; - } + } + } // / if ID - } + return false; + } - // Add any addr custom fields for addr1+addr2 - // no need if simpliefied or count parameters passed - if (!$simplified && !$count && !$onlyColumns){ - $addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); - if (is_array($addrCustomFields) && count($addrCustomFields) > 0){ + /** + * returns company detail lines + * + * @param array $args Associative array of arguments + * + * @return array of company lines + */ + public function getCompanies( $args = array() ) { - foreach ($addrCustomFields as $cK => $cF){ + global $zbs; - // custom field key - $cfKey = 'addr_'.$cK; - $cfKey2 = 'secaddr_'.$cK; + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => '', // searches which fields? + 'inArr' => false, + 'isTagged' => false, // 1x INT OR array(1,2,3) + 'isNotTagged' => false, // 1x INT OR array(1,2,3) + 'ownedBy' => false, + 'externalSource' => false, // e.g. paypal + 'olderThan' => false, // uts + 'newerThan' => false, // uts + 'hasStatus' => false, // Lead (this takes over from the quick filter post 19/6/18) + 'otherStatus' => false, // status other than 'Lead' + 'hasContact' => false, // has a contact of this ID associated with it + 'quickFilters' => false, // booo + + // addr + 'inCounty' => false, // Hertfordshire + 'inPostCode' => false, // AL1 1AA + 'inCountry' => false, // United Kingdom + 'notInCounty' => false, // Hertfordshire + 'notInPostCode' => false, // AL1 1AA + 'notInCountry' => false, // United Kingdom + + // generic assignments - requires both + // Where the link relationship is OBJECT -> CONTACT + 'hasObjIDLinkedTo' => false, // e.g. quoteid 123 + 'hasObjTypeLinkedTo' => false, // e.g. ZBS_TYPE_QUOTE + + // generic assignments - requires both + // Where the link relationship is CONTACT -> OBJECT + 'isLinkedToObjID' => false, // e.g. quoteid 123 + 'isLinkedToObjType' => false, // e.g. ZBS_TYPE_QUOTE + + // returns + 'count' => false, + 'withCustomFields' => true, + 'withQuotes' => false, // Will only be operable when Company<->Quotes established + 'withInvoices' => false, + 'withTransactions' => false, + 'withTasks' => false, + 'withTags' => false, + 'withOwner' => false, + 'withLogs' => false, + 'withLastLog' => false, + 'withValues' => false, // if passed, returns with 'total' 'invoices_total' 'transactions_total' etc. (requires getting all obj, use sparingly) + 'withContacts' => true, // return ['contact'] objs + 'withExternalSources' => false, + 'withExternalSourcesGrouped' => false, + 'simplified' => false, // returns just id,name,created (for typeaheads) + 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 100, + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + global $ZBSCRM_t, $wpdb, $zbs; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; + $whereCase = 'AND'; + + #} ============= PRE-QUERY ============ + + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); + + #} If just count, or simplified, turn off any extra gumpf + if ( $count || $simplified ) { + $withCustomFields = false; + $withTags = false; + $withOwner = false; + $withLogs = false; + $withLastLog = false; + $withContacts = false; + $withTasks = false; + $withExternalSources = false; + $withExternalSourcesGrouped = false; + } - // address custom field (e.g. 'house name') it'll be passed here as 'house-name' - // ... problem is mysql does not like that :) so we have to chage here: - // in this case we prepend address cf's with addr_ and we switch - for _ - $cKey = 'addrcf_'.str_replace('-','_',$cK); - $cKey2 = 'secaddrcf_'.str_replace('-','_',$cK); + #} If onlyColumns, validate + if ( $onlyColumns ) { - // we also check the $sortByField in case that's the same cf - if ($cfKey == $sortByField) $sortByField = $cKey; - if ($cfKey2 == $sortByField) $sortByField = $cKey2; + #} onlyColumns build out a field arr + if ( is_array( $onlyColumns ) && count( $onlyColumns ) > 0 ) { - // addr 1 - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey; - // add params - $params[] = $cfKey; $params[] = ZBS_TYPE_COMPANY; - // addr 2 - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey2; - // add params - $params[] = $cfKey2; $params[] = ZBS_TYPE_COMPANY; + $onlyColumnsFieldArr = array(); + foreach ( $onlyColumns as $col ) { - } + // find db col key from field key (e.g. fname => zbsc_fname) + $dbCol = ''; + if ( isset( $this->objectModel[ $col ] ) && isset( $this->objectModel[ $col ]['fieldname'] ) ) { + $dbCol = $this->objectModel[ $col ]['fieldname']; + } + if ( ! empty( $dbCol ) ) { - } + $onlyColumnsFieldArr[ $dbCol ] = $col; - } + } + } + } - // ==== TOTAL VALUES + // if legit cols: + if ( isset( $onlyColumnsFieldArr ) && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - // Calculate total vals etc. with SQL - if (!$simplified && !$count && $withValues && !$onlyColumns){ + $onlyColumns = true; - // arguably, if getting $withInvoices etc. may be more performant to calc this in php in AFTER loop, - // ... for now as a fair guess, this'll be most performant: - // ... we calc total by adding invs + trans below :) + // If onlyColumns, turn off extras + $withCustomFields = false; + $withTags = false; + $withOwner = false; + $withLogs = false; + $withLastLog = false; + $withContacts = false; + $withTasks = false; + $withExternalSources = false; + $withExternalSourcesGrouped = false; - // only include transactions with statuses which should be included in total value: - $transStatusQueryAdd = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); - // include invoices without deleted status in the total value for invoices_total_inc_deleted: - $inv_status_query_add = $this->DAL()->invoices->get_invoice_status_except_deleted_for_query(); + } else { - // When Company<->Quotes: - // $extraSelect .= ',(SELECT SUM(quotestotal.zbsq_value) FROM '.$ZBSCRM_t['quotes'].' as quotestotal WHERE quotestotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_QUOTE." AND zbsol_objtype_to = ".ZBS_TYPE_COMPANY." AND zbsol_objid_to = company.ID)) as quotes_total"; - // invs: - $extraSelect .= ',(SELECT IFNULL(SUM(invstotal.zbsi_total),0) FROM ' . $ZBSCRM_t['invoices'] . ' as invstotal WHERE invstotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ') as invoices_total'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // invs including deleted: - $extraSelect .= ',(SELECT SUM(invstotalincdeleted.zbsi_total) FROM ' . $ZBSCRM_t['invoices'] . ' as invstotalincdeleted WHERE invstotalincdeleted.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as invoices_total_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // invs count: - $extraSelect .= ',(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ') as invoices_count'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // invs count including deleted: - $extraSelect .= ',(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as invoices_count_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // deny + $onlyColumns = false; - // trans (with status): - $extraSelect .= ',(SELECT SUM(transtotal.zbst_total) FROM '.$ZBSCRM_t['transactions'].' as transtotal WHERE transtotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_TRANSACTION." AND zbsol_objtype_to = ".ZBS_TYPE_COMPANY." AND zbsol_objid_to = company.ID)".$transStatusQueryAdd.") as transactions_total"; - // paid balance against invs (also in getCompany) - // (this allows us to subtract from totals to get a true figure where transactions are part/whole payments for invs) - /* + } + } - This selects transactions - where there is a link to an invoice - where that invoice has a link to this contact: + #} Custom Fields + // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. + if ( $withCustomFields ) { - ========== + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_COMPANY ) ); - SELECT * FROM wp_zbs_transactions trans - WHERE trans.ID IN - - ( - SELECT DISTINCT zbsol_objid_from FROM `wp_zbs_object_links` - WHERE zbsol_objtype_from = 5 - AND zbsol_objtype_to = 4 - AND zbsol_objid_to IN + #} Cycle through + build into query + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { - ( + // custom field (e.g. 'third name') it'll be passed here as 'third-name' + // ... problem is mysql does not like that :) so we have to chage here: + // in this case we prepend cf's with cf_ and we switch - for _ + $cKey = 'cf_' . str_replace( '-', '_', $cK ); - SELECT DISTINCT zbsol_objid_from FROM `wp_zbs_object_links` - WHERE zbsol_objtype_from = 4 AND zbsol_objtype_to = 1 AND zbsol_objid_to = 1 + // we also check the $sortByField in case that's the same cf + if ( $cK == $sortByField ) { - ) + // sort by + $sortByField = $cKey; - ) + // check if sort needs any CAST (e.g. numeric): + $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); + } - */ - $extraSelect .= ',(SELECT SUM(assignedtranstotal.zbst_total) FROM '.$ZBSCRM_t['transactions'].' assignedtranstotal WHERE assignedtranstotal.ID IN '; - $extraSelect .= '(SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_TRANSACTION.' AND zbsol_objtype_to = '.ZBS_TYPE_INVOICE.' AND zbsol_objid_to IN '; - $extraSelect .= '(SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_INVOICE.' AND zbsol_objtype_to = '.ZBS_TYPE_COMPANY.' AND zbsol_objid_to = company.ID)'; - $extraSelect .= ')'.$transStatusQueryAdd.') as transactions_paid_total'; - } + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ' . $cKey; - // ==== / TOTAL VALUES + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_COMPANY; - #} ============ / PRE-QUERY =========== + } + } + } - #} Build query - $query = "SELECT company.*".$extraSelect." FROM ".$ZBSCRM_t['companies'].' as company'.$joinQ; + // Add any addr custom fields for addr1+addr2 + // no need if simpliefied or count parameters passed + if ( ! $simplified && ! $count && ! $onlyColumns ) { + $addrCustomFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); + if ( is_array( $addrCustomFields ) && count( $addrCustomFields ) > 0 ) { + + foreach ( $addrCustomFields as $cK => $cF ) { + + // custom field key + $cfKey = 'addr_' . $cK; + $cfKey2 = 'secaddr_' . $cK; + + // address custom field (e.g. 'house name') it'll be passed here as 'house-name' + // ... problem is mysql does not like that :) so we have to chage here: + // in this case we prepend address cf's with addr_ and we switch - for _ + $cKey = 'addrcf_' . str_replace( '-', '_', $cK ); + $cKey2 = 'secaddrcf_' . str_replace( '-', '_', $cK ); + + // we also check the $sortByField in case that's the same cf + if ( $cfKey == $sortByField ) { + $sortByField = $cKey; + } + if ( $cfKey2 == $sortByField ) { + $sortByField = $cKey2; + } + + // addr 1 + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey; + // add params + $params[] = $cfKey; + $params[] = ZBS_TYPE_COMPANY; + // addr 2 + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = company.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey2; + // add params + $params[] = $cfKey2; + $params[] = ZBS_TYPE_COMPANY; + + } + } + } + + // ==== TOTAL VALUES + + // Calculate total vals etc. with SQL + if ( ! $simplified && ! $count && $withValues && ! $onlyColumns ) { + + // arguably, if getting $withInvoices etc. may be more performant to calc this in php in AFTER loop, + // ... for now as a fair guess, this'll be most performant: + // ... we calc total by adding invs + trans below :) + + // only include transactions with statuses which should be included in total value: + $transStatusQueryAdd = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); + // include invoices without deleted status in the total value for invoices_total_inc_deleted: + $inv_status_query_add = $this->DAL()->invoices->get_invoice_status_except_deleted_for_query(); + + // When Company<->Quotes: + // $extraSelect .= ',(SELECT SUM(quotestotal.zbsq_value) FROM '.$ZBSCRM_t['quotes'].' as quotestotal WHERE quotestotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_QUOTE." AND zbsol_objtype_to = ".ZBS_TYPE_COMPANY." AND zbsol_objid_to = company.ID)) as quotes_total"; + // invs: + $extraSelect .= ',(SELECT IFNULL(SUM(invstotal.zbsi_total),0) FROM ' . $ZBSCRM_t['invoices'] . ' as invstotal WHERE invstotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ') as invoices_total'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // invs including deleted: + $extraSelect .= ',(SELECT SUM(invstotalincdeleted.zbsi_total) FROM ' . $ZBSCRM_t['invoices'] . ' as invstotalincdeleted WHERE invstotalincdeleted.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as invoices_total_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // invs count: + $extraSelect .= ',(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ') as invoices_count'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // invs count including deleted: + $extraSelect .= ',(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)) as invoices_count_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + + // trans (with status): + $extraSelect .= ',(SELECT SUM(transtotal.zbst_total) FROM ' . $ZBSCRM_t['transactions'] . ' as transtotal WHERE transtotal.ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $transStatusQueryAdd . ') as transactions_total'; + // paid balance against invs (also in getCompany) + // (this allows us to subtract from totals to get a true figure where transactions are part/whole payments for invs) + /* + This selects transactions + where there is a link to an invoice + where that invoice has a link to this contact: + + ========== + + SELECT * FROM wp_zbs_transactions trans + WHERE trans.ID IN + + ( + SELECT DISTINCT zbsol_objid_from FROM `wp_zbs_object_links` + WHERE zbsol_objtype_from = 5 + AND zbsol_objtype_to = 4 + AND zbsol_objid_to IN + + ( + + SELECT DISTINCT zbsol_objid_from FROM `wp_zbs_object_links` + WHERE zbsol_objtype_from = 4 AND zbsol_objtype_to = 1 AND zbsol_objid_to = 1 + + ) + + ) + + + */ + $extraSelect .= ',(SELECT SUM(assignedtranstotal.zbst_total) FROM ' . $ZBSCRM_t['transactions'] . ' assignedtranstotal WHERE assignedtranstotal.ID IN '; + $extraSelect .= '(SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objid_to IN '; + $extraSelect .= '(SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)'; + $extraSelect .= ')' . $transStatusQueryAdd . ') as transactions_paid_total'; + } - #} Count override - if ($count) $query = "SELECT COUNT(company.ID) FROM ".$ZBSCRM_t['companies'].' as company'.$joinQ; + // ==== / TOTAL VALUES - #} simplified override - if ($simplified) $query = "SELECT company.ID as id,company.zbsco_name as name,company.zbsco_created as created,company.zbsco_email as email FROM ".$ZBSCRM_t['companies'].' as company'.$joinQ; + #} ============ / PRE-QUERY =========== - #} onlyColumns override - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + #} Build query + $query = 'SELECT company.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['companies'] . ' as company' . $joinQ; - $columnStr = ''; - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(company.ID) FROM ' . $ZBSCRM_t['companies'] . ' as company' . $joinQ; + } - if (!empty($columnStr)) $columnStr .= ','; - // this presumes str is db-safe? could do with sanitation? - $columnStr .= $colDBKey; + #} simplified override + if ( $simplified ) { + $query = 'SELECT company.ID as id,company.zbsco_name as name,company.zbsco_created as created,company.zbsco_email as email FROM ' . $ZBSCRM_t['companies'] . ' as company' . $joinQ; + } - } + #} onlyColumns override + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - $query = "SELECT ".$columnStr." FROM ".$ZBSCRM_t['companies'].' as company'.$joinQ; + $columnStr = ''; + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - } + if ( ! empty( $columnStr ) ) { + $columnStr .= ','; + } + // this presumes str is db-safe? could do with sanitation? + $columnStr .= $colDBKey; - #} ============= WHERE ================ + } - #} Add Search phrase - if (!empty($searchPhrase)){ + $query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['companies'] . ' as company' . $joinQ; - // search? - ALL THESE COLS should probs have index of FULLTEXT in db? - $searchWheres = array(); - $searchWheres['search_ID'] = array('ID','=','%d',$searchPhrase); - $searchWheres['search_name'] = array('zbsco_name','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_email'] = array('zbsco_email','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_maintel'] = array('zbsco_maintel','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_sectel'] = array('zbsco_sectel','LIKE','%s','%'.$searchPhrase.'%'); + } - // address elements - $searchWheres['search_addr1'] = array('zbsco_addr1','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_addr2'] = array('zbsco_addr2','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_city'] = array('zbsco_city','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_county'] = array('zbsco_county','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_country'] = array('zbsco_country','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_postcode'] = array('zbsco_postcode','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_secaddr1'] = array('zbsco_secaddr1','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_secaddr2'] = array('zbsco_secaddr2','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_seccity'] = array('zbsco_seccity','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_seccounty'] = array('zbsco_seccounty','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_seccountry'] = array('zbsco_seccountry','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_secpostcode'] = array('zbsco_secpostcode','LIKE','%s','%'.$searchPhrase.'%'); + #} ============= WHERE ================ + + #} Add Search phrase + if ( ! empty( $searchPhrase ) ) { + + // search? - ALL THESE COLS should probs have index of FULLTEXT in db? + $searchWheres = array(); + $searchWheres['search_ID'] = array( 'ID', '=', '%d', $searchPhrase ); + $searchWheres['search_name'] = array( 'zbsco_name', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_email'] = array( 'zbsco_email', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_maintel'] = array( 'zbsco_maintel', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_sectel'] = array( 'zbsco_sectel', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + + // address elements + $searchWheres['search_addr1'] = array( 'zbsco_addr1', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_addr2'] = array( 'zbsco_addr2', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_city'] = array( 'zbsco_city', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_county'] = array( 'zbsco_county', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_country'] = array( 'zbsco_country', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_postcode'] = array( 'zbsco_postcode', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_secaddr1'] = array( 'zbsco_secaddr1', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_secaddr2'] = array( 'zbsco_secaddr2', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_seccity'] = array( 'zbsco_seccity', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_seccounty'] = array( 'zbsco_seccounty', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_seccountry'] = array( 'zbsco_seccountry', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_secpostcode'] = array( 'zbsco_secpostcode', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + + // social + $searchWheres['search_tw'] = array( 'zbsco_tw', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_li'] = array( 'zbsco_li', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_fb'] = array( 'zbsco_fb', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + + // 3.0.13 - Added ability to search custom fields (optionally) + $customFieldSearch = zeroBSCRM_getSetting( 'customfieldsearch' ); + if ( $customFieldSearch == 1 ) { + + // simplistic add + // NOTE: This IGNORES ownership of custom field lines. + $searchWheres['search_customfields'] = array( 'ID', 'IN', '(SELECT zbscf_objid FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objval LIKE %s AND zbscf_objtype = ' . ZBS_TYPE_COMPANY . ')', '%' . $searchPhrase . '%' ); - // social - $searchWheres['search_tw'] = array('zbsco_tw','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_li'] = array('zbsco_li','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_fb'] = array('zbsco_fb','LIKE','%s','%'.$searchPhrase.'%'); + } - // 3.0.13 - Added ability to search custom fields (optionally) - $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); - if ($customFieldSearch == 1){ - - // simplistic add - // NOTE: This IGNORES ownership of custom field lines. - $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE zbscf_objval LIKE %s AND zbscf_objtype = ".ZBS_TYPE_COMPANY.")",'%'.$searchPhrase.'%'); + // This generates a query like 'zbsco_fname LIKE %s OR zbsco_lname LIKE %s', + // which we then need to include as direct subquery (below) in main query :) + $searchQueryArr = $this->buildWheres( $searchWheres, '', array(), 'OR', false ); - } + if ( is_array( $searchQueryArr ) && isset( $searchQueryArr['where'] ) && ! empty( $searchQueryArr['where'] ) ) { - // This generates a query like 'zbsco_fname LIKE %s OR zbsco_lname LIKE %s', - // which we then need to include as direct subquery (below) in main query :) - $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - - if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ + // add it + $wheres['direct'][] = array( '(' . $searchQueryArr['where'] . ')', $searchQueryArr['params'] ); - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + } + } - } + #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { - } - - #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) - if (is_array($inArr) && count($inArr) > 0){ + // clean for ints + $inArrChecked = array(); + foreach ( $inArr as $x ) { + $inArrChecked[] = (int) $x; } - // clean for ints - $inArrChecked = array(); foreach ($inArr as $x){ $inArrChecked[] = (int)$x; } + // add where + $wheres['inarray'] = array( 'ID', 'IN', '(' . implode( ',', $inArrChecked ) . ')' ); - // add where - $wheres['inarray'] = array('ID','IN','('.implode(',',$inArrChecked).')'); + } - } + #} Owned by + if ( is_int( $ownedBy ) && ! empty( $ownedBy ) && $ownedBy > 0 ) { - #} Owned by - if (is_int($ownedBy) && !empty($ownedBy) && $ownedBy > 0){ - - // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) - // but this is only here until MIGRATED to db2 globally - //$wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); - // Use obj links now - $wheres['ownedBy'] = array('zbs_owner','=','%s',$ownedBy); + // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) + // but this is only here until MIGRATED to db2 globally + // $wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); + // Use obj links now + $wheres['ownedBy'] = array( 'zbs_owner', '=', '%s', $ownedBy ); - } + } - // External sources - if ( !empty( $externalSource ) ){ + // External sources + if ( ! empty( $externalSource ) ) { - // NO owernship built into this, check when roll out multi-layered ownsership - $wheres['externalsource'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_COMPANY." AND zbss_source = %s)",$externalSource); + // NO owernship built into this, check when roll out multi-layered ownsership + $wheres['externalsource'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_COMPANY . ' AND zbss_source = %s)', $externalSource ); - } + } // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed // quick addition for mike @@ -1319,7 +1443,6 @@ public function getCompanies($args=array()){ // has contact associated with it if ( ! empty( $hasContact ) && $hasContact > 0 ) $wheres['hasContact'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' ); - // generic obj links, e.g. quotes, invs, trans // e.g. contact(s) assigned to inv 123 // Where the link relationship is OBJECT -> CONTACT @@ -1338,14 +1461,14 @@ public function getCompanies($args=array()){ } // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed - #} Quick filters - adapted from DAL1 (probs can be slicker) - if (is_array($quickFilters) && count($quickFilters) > 0){ + #} Quick filters - adapted from DAL1 (probs can be slicker) + if ( is_array( $quickFilters ) && count( $quickFilters ) > 0 ) { - // cycle through - foreach ($quickFilters as $qFilter){ + // cycle through + foreach ( $quickFilters as $qFilter ) { - // where status = x - // USE hasStatus above now... + // where status = x + // USE hasStatus above now... if ( str_starts_with( $qFilter, 'status_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $quick_filter_status = substr( $qFilter, 7 ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -1353,134 +1476,136 @@ public function getCompanies($args=array()){ } elseif ( str_starts_with( $qFilter, 'notcontactedin' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // check - $notcontactedinDays = (int)substr($qFilter,14); - $notcontactedinDaysSeconds = $notcontactedinDays*86400; - $wheres['notcontactedinx'] = array('zbsco_lastcontacted','<','%d',time()-$notcontactedinDaysSeconds); + // check + $notcontactedinDays = (int) substr( $qFilter, 14 ); + $notcontactedinDaysSeconds = $notcontactedinDays * 86400; + $wheres['notcontactedinx'] = array( 'zbsco_lastcontacted', '<', '%d', time() - $notcontactedinDaysSeconds ); } elseif ( str_starts_with( $qFilter, 'olderthan' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // check - $olderThanDays = (int)substr($qFilter,9); - $olderThanDaysSeconds = $olderThanDays*86400; - $wheres['olderthanx'] = array('zbsco_created','<','%d',time()-$olderThanDaysSeconds); + // check + $olderThanDays = (int) substr( $qFilter, 9 ); + $olderThanDaysSeconds = $olderThanDays * 86400; + $wheres['olderthanx'] = array( 'zbsco_created', '<', '%d', time() - $olderThanDaysSeconds ); } else { - // normal/hardtyped - - switch ($qFilter){ - + // normal/hardtyped - case 'lead': + switch ( $qFilter ) { - // hack "leads only" - adapted from DAL1 (probs can be slicker) - $wheres['quickfilterlead'] = array('zbsco_status','LIKE','%s','Lead'); + case 'lead': + // hack "leads only" - adapted from DAL1 (probs can be slicker) + $wheres['quickfilterlead'] = array( 'zbsco_status', 'LIKE', '%s', 'Lead' ); - break; + break; + case 'customer': + // hack - adapted from DAL1 (probs can be slicker) + $wheres['quickfiltercustomer'] = array( 'zbsco_status', 'LIKE', '%s', 'Customer' ); - case 'customer': + break; - // hack - adapted from DAL1 (probs can be slicker) - $wheres['quickfiltercustomer'] = array( 'zbsco_status', 'LIKE', '%s', 'Customer' ); + } // / switch - break; + } // / hardtyped - } // / switch - - } // / hardtyped - - } - } // / quickfilters + } + } // / quickfilters - #} Is Tagged (expects 1 tag ID OR array) + #} Is Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isTagged) && count($isTagged) == 1) $isTagged = $isTagged[0]; + // catch 1 item arr + if ( is_array( $isTagged ) && count( $isTagged ) == 1 ) { + $isTagged = $isTagged[0]; + } if ( ! empty( $isTagged ) && ! is_array( $isTagged ) && $isTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = company.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_COMPANY,$isTagged)); + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = company.ID AND zbstl_tagid = %d) > 0)', array( ZBS_TYPE_COMPANY, $isTagged ) ); - } else if (is_array($isTagged) && count($isTagged) > 0){ + } elseif ( is_array( $isTagged ) && count( $isTagged ) > 0 ) { - // foreach in array :) - $tagStr = ''; - foreach ($isTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + // foreach in array :) + $tagStr = ''; + foreach ( $isTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = company.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_COMPANY,$tagStr)); + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = company.ID AND zbstl_tagid IN (%s)) > 0)', array( ZBS_TYPE_COMPANY, $tagStr ) ); - } - #} Is NOT Tagged (expects 1 tag ID OR array) + } + } + #} Is NOT Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isNotTagged) && count($isNotTagged) == 1) $isNotTagged = $isNotTagged[0]; - - if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // catch 1 item arr + if ( is_array( $isNotTagged ) && count( $isNotTagged ) == 1 ) { + $isNotTagged = $isNotTagged[0]; + } - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = company.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_COMPANY,$isNotTagged)); + if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } else if (is_array($isNotTagged) && count($isNotTagged) > 0){ + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = company.ID AND zbstl_tagid = %d) = 0)', array( ZBS_TYPE_COMPANY, $isNotTagged ) ); - // foreach in array :) - $tagStr = ''; - foreach ($isNotTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + } elseif ( is_array( $isNotTagged ) && count( $isNotTagged ) > 0 ) { - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = company.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_COMPANY,$tagStr)); + // foreach in array :) + $tagStr = ''; + foreach ( $isNotTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - } + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = company.ID AND zbstl_tagid IN (%s)) = 0)', array( ZBS_TYPE_COMPANY, $tagStr ) ); - + } + } - #} ============ / WHERE =============== + #} ============ / WHERE =============== - #} ============ SORT ============== + #} ============ SORT ============== - // Obj Model based sort conversion - // converts 'addr1' => 'zbsco_addr1' generically - if (isset($this->objectModel[$sortByField]) && isset($this->objectModel[$sortByField]['fieldname'])) $sortByField = $this->objectModel[$sortByField]['fieldname']; + // Obj Model based sort conversion + // converts 'addr1' => 'zbsco_addr1' generically + if ( isset( $this->objectModel[ $sortByField ] ) && isset( $this->objectModel[ $sortByField ]['fieldname'] ) ) { + $sortByField = $this->objectModel[ $sortByField ]['fieldname']; + } // include invoices without deleted status in the total value for invoices_total_inc_deleted: $inv_status_query_add = $this->DAL()->invoices->get_invoice_status_except_deleted_for_query(); - // Mapped sorts - // This catches listview and other exception sort cases - $sort_map = array( - 'id' => 'ID', - 'assigned' => 'zbsco_owner', - 'fullname' => 'zbsco_name', - 'status' => 'zbsco_status', - 'email' => 'zbsco_email', - - // contacts (count) - 'contacts' => '(SELECT COUNT(ID) FROM '.$ZBSCRM_t['contacts'].' WHERE ID IN (SELECT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_CONTACT.' AND zbsol_objtype_to = '.ZBS_TYPE_COMPANY.' AND zbsol_objid_to = company.ID))', - - // has & counts (same queries) + // Mapped sorts + // This catches listview and other exception sort cases + $sort_map = array( + 'id' => 'ID', + 'assigned' => 'zbsco_owner', + 'fullname' => 'zbsco_name', + 'status' => 'zbsco_status', + 'email' => 'zbsco_email', + + // contacts (count) + 'contacts' => '(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['contacts'] . ' WHERE ID IN (SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID))', + + // has & counts (same queries) // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase 'hasinvoice' => '(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID))', 'hastransaction' => '(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['transactions'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID))', @@ -1488,1935 +1613,2134 @@ public function getCompanies($args=array()){ 'invoicecount' => '(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['invoices'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID)' . $inv_status_query_add . ')', 'transactioncount' => '(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['transactions'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = company.ID))', // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // following will only work if obj total value subqueries triggered above ^ - 'totalvalue' => '((IFNULL(invoices_total,0) + IFNULL(transactions_total,0)) - IFNULL(transactions_paid_total,0))', // custom sort by total invoice value + transaction value - paid transactions (as mimicking tidy_contact php logic into SQL) - 'transactiontotal' => 'transactions_total', - 'invoicetotal' => 'invoices_total', + // following will only work if obj total value subqueries triggered above ^ + 'totalvalue' => '((IFNULL(invoices_total,0) + IFNULL(transactions_total,0)) - IFNULL(transactions_paid_total,0))', // custom sort by total invoice value + transaction value - paid transactions (as mimicking tidy_contact php logic into SQL) + 'transactiontotal' => 'transactions_total', + 'invoicetotal' => 'invoices_total', + + // When Company<->Quotes: + /* + 'hasquote' => '(SELECT COUNT(ID) FROM '.$ZBSCRM_t['quotes'].' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_QUOTE.' AND zbsol_objtype_to = '.ZBS_TYPE_COMPANY.' AND zbsol_objid_to = company.ID))', + 'quotetotal' => 'quotes_total', + 'quotecount' => '(SELECT COUNT(ID) FROM '.$ZBSCRM_t['quotes'].' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_QUOTE.' AND zbsol_objtype_to = '.ZBS_TYPE_COMPANY.' AND zbsol_objid_to = company.ID))', + */ - // When Company<->Quotes: - /* - 'hasquote' => '(SELECT COUNT(ID) FROM '.$ZBSCRM_t['quotes'].' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_QUOTE.' AND zbsol_objtype_to = '.ZBS_TYPE_COMPANY.' AND zbsol_objid_to = company.ID))', - 'quotetotal' => 'quotes_total', - 'quotecount' => '(SELECT COUNT(ID) FROM '.$ZBSCRM_t['quotes'].' WHERE ID IN (SELECT DISTINCT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_QUOTE.' AND zbsol_objtype_to = '.ZBS_TYPE_COMPANY.' AND zbsol_objid_to = company.ID))', - */ + ); - ); - - if ( array_key_exists( $sortByField, $sort_map ) ) { + if ( array_key_exists( $sortByField, $sort_map ) ) { - $sortByField = $sort_map[ $sortByField ]; + $sortByField = $sort_map[ $sortByField ]; - } + } - #} ============ / SORT ============== + #} ============ / SORT ============== - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; + #} CHECK this + reset to default if faulty + if ( ! in_array( $whereCase, array( 'AND', 'OR' ) ) ) { + $whereCase = 'AND'; + } - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params, $whereCase ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'contact' ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'contact'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); - - try { + try { - #} Prep & run query - $queryObj = $this->prepare($query,$params); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - #} Catch count + return if requested - if ($count) return $wpdb->get_var($queryObj); + #} Catch count + return if requested + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - } catch (Exception $e){ + } catch ( Exception $e ) { - #} General SQL Err - $this->catchSQLError($e); + #} General SQL Err + $this->catchSQLError( $e ); - } + } - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - #} simplified override - if ($simplified){ + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - $resArr = array( - 'id' => $resDataLine->id, - 'name' => $resDataLine->name, - 'created' => $resDataLine->created, - 'email' => $resDataLine->email - ); + #} simplified override + if ( $simplified ) { - } else if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + $resArr = array( + 'id' => $resDataLine->id, + 'name' => $resDataLine->name, + 'created' => $resDataLine->created, + 'email' => $resDataLine->email, + ); - // only coumns return. - $resArr = array(); - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + } elseif ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - if (isset($resDataLine->$colDBKey)) $resArr[$colStr] = $resDataLine->$colDBKey; + // only coumns return. + $resArr = array(); + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - } + if ( isset( $resDataLine->$colDBKey ) ) { + $resArr[ $colStr ] = $resDataLine->$colDBKey; + } + } + } else { + // tidy + $resArr = $this->tidy_company( $resDataLine, $withCustomFields ); - } else { - - // tidy - $resArr = $this->tidy_company($resDataLine,$withCustomFields); + } - } + if ( $withTags ) { - if ($withTags){ + // add all tags lines + $resArr['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_COMPANY, + 'objid' => $resDataLine->ID, + ) + ); - // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_COMPANY,'objid'=>$resDataLine->ID)); + } - } + #} With most recent log? #DB1LEGACY (TOMOVE) + if ( $withLastLog ) { - #} With most recent log? #DB1LEGACY (TOMOVE) - if ($withLastLog){ + // doesn't return singular, for now using arr + $potentialLogs = $this->DAL()->logs->getLogsForObj( + array( - // doesn't return singular, for now using arr - $potentialLogs = $this->DAL()->logs->getLogsForObj(array( + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $resDataLine->ID, - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $resDataLine->ID, - - 'incMeta' => true, + 'incMeta' => true, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1 + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, - )); + ) + ); - if (is_array($potentialLogs) && count($potentialLogs) > 0) $resArr['lastlog'] = $potentialLogs[0]; + if ( is_array( $potentialLogs ) && count( $potentialLogs ) > 0 ) { + $resArr['lastlog'] = $potentialLogs[0]; + } - // COMPANY logs specifically - // doesn't return singular, for now using arr - $potentialLogs = $this->DAL()->logs->getLogsForObj( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - array( + // COMPANY logs specifically + // doesn't return singular, for now using arr + $potentialLogs = $this->DAL()->logs->getLogsForObj( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $resDataLine->ID, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $resDataLine->ID, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - 'notetypes' => $zbs->DAL->logs->contact_log_types, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + 'notetypes' => $zbs->DAL->logs->contact_log_types, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - 'incMeta' => true, + 'incMeta' => true, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1, + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, - ) - ); + ) + ); - if (is_array($potentialLogs) && count($potentialLogs) > 0) $resArr['lastcontactlog'] = $potentialLogs[0]; - - } - - #} With Assigned? - if ($withOwner){ + if ( is_array( $potentialLogs ) && count( $potentialLogs ) > 0 ) { + $resArr['lastcontactlog'] = $potentialLogs[0]; + } + } - $resArr['owner'] = zeroBS_getOwner($resDataLine->ID,true,'zerobs_company',$resDataLine->zbs_owner); + #} With Assigned? + if ( $withOwner ) { - } + $resArr['owner'] = zeroBS_getOwner( $resDataLine->ID, true, 'zerobs_company', $resDataLine->zbs_owner ); - if ($withContacts){ + } - // add all assigned contacts/companies - $resArr['contacts'] = $this->DAL()->contacts->getContacts(array( - 'isLinkedToObjType'=>ZBS_TYPE_COMPANY, - 'isLinkedToObjID'=>$resDataLine->ID, - 'page'=>-1, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + if ( $withContacts ) { - } + // add all assigned contacts/companies + $resArr['contacts'] = $this->DAL()->contacts->getContacts( + array( + 'isLinkedToObjType' => ZBS_TYPE_COMPANY, + 'isLinkedToObjID' => $resDataLine->ID, + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); - if ($withInvoices){ - //DAL3 ver, more perf, gets all - $resArr['invoices'] = $zbs->DAL->invoices->getInvoices(array( + } - 'assignedCompany' => $resDataLine->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE) + if ( $withInvoices ) { + // DAL3 ver, more perf, gets all + $resArr['invoices'] = $zbs->DAL->invoices->getInvoices( + array( - )); + 'assignedCompany' => $resDataLine->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), - } + ) + ); - if ( $withQuotes ) { - - //DAL3 ver, more perf, gets all - $resArr['quotes'] = $zbs->DAL->quotes->getQuotes(array( + } - 'assignedCompany' => $resDataLine->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE) + if ( $withQuotes ) { - )); + // DAL3 ver, more perf, gets all + $resArr['quotes'] = $zbs->DAL->quotes->getQuotes( + array( - } + 'assignedCompany' => $resDataLine->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), - #} ... brutal for mvp #DB1LEGACY (TOMOVE) - if ($withTransactions){ - - //DAL3 ver, more perf, gets all - $resArr['transactions'] = $zbs->DAL->transactions->getTransactions(array( + ) + ); - 'assignedCompany' => $resDataLine->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION) + } - )); + #} ... brutal for mvp #DB1LEGACY (TOMOVE) + if ( $withTransactions ) { - } + // DAL3 ver, more perf, gets all + $resArr['transactions'] = $zbs->DAL->transactions->getTransactions( + array( - #} ... brutal for mvp #DB1LEGACY (TOMOVE) - if ($withTasks){ - - $res['tasks'] = $zbs->DAL->events->getEvents(array( + 'assignedCompany' => $resDataLine->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), - 'assignedCompany' => $resDataLine->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK), - 'sortByField' => 'zbse_start', - 'sortOrder' => 'DESC', - 'withAssigned' => false // no need, it's assigned to this obj already + ) + ); - )); + } - } + #} ... brutal for mvp #DB1LEGACY (TOMOVE) + if ( $withTasks ) { - // simplistic, could be optimised (though low use means later.) - if ( $withExternalSources ){ - - $res['external_sources'] = $zbs->DAL->getExternalSources( array( - - 'objectID' => $resDataLine->ID, - 'objectType' => ZBS_TYPE_COMPANY, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + $res['tasks'] = $zbs->DAL->events->getEvents( + array( - )); + 'assignedCompany' => $resDataLine->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), + 'sortByField' => 'zbse_start', + 'sortOrder' => 'DESC', + 'withAssigned' => false, // no need, it's assigned to this obj already - } - if ( $withExternalSourcesGrouped ){ - - $res['external_sources'] = $zbs->DAL->getExternalSources( -1, array( - - 'objectID' => $resDataLine->ID, - 'objectType' => ZBS_TYPE_COMPANY, - 'grouped_by_source' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ) - - )); - - } - - //} - - // =================================================== - // ========== / #DB1LEGACY (TOMOVE) - // =================================================== - - $res[] = $resArr; - - } - } - - return $res; - } - - /** - * Returns a count of companies (owned) - * .. inc by status - * - * @return int count - */ - public function getCompanyCount($args=array()){ - - #} ============ LOAD ARGS ============= - $defaultArgs = array( + ) + ); - // Search/Filtering (leave as false to ignore) - 'withStatus' => false, // will be str if used - - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - $whereArr = array(); - - if ($withStatus !== false && !empty($withStatus)) $whereArr['status'] = array('zbsco_status','=','%s',$withStatus); - - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_COMPANY, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - } + } + // simplistic, could be optimised (though low use means later.) + if ( $withExternalSources ) { + $res['external_sources'] = $zbs->DAL->getExternalSources( + array( - /** - * adds or updates a company object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateCompany($args=array()){ + 'objectID' => $resDataLine->ID, + 'objectType' => ZBS_TYPE_COMPANY, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - global $ZBSCRM_t,$wpdb,$zbs; - - #} Retrieve any cf - $customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_COMPANY)); - $addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); - - #} ============ LOAD ARGS ============= - $defaultArgs = array( + ) + ); - 'id' => -1, - 'owner' => -1, + } + if ( $withExternalSourcesGrouped ) { - // fields (directly) - 'data' => array( + $res['external_sources'] = $zbs->DAL->getExternalSources( + -1, + array( - - 'status' => '', - 'name' => '', - 'email' => '', - 'addr1' => '', - 'addr2' => '', - 'city' => '', - 'county' => '', - 'country' => '', - 'postcode' => '', - 'secaddr1' => '', - 'secaddr2' => '', - 'seccity' => '', - 'seccounty' => '', - 'seccountry' => '', - 'secpostcode' => '', - 'maintel' => '', - 'sectel' => '', - 'wpid' => '', - 'avatar' => '', - 'tw' => '', - 'li' => '', - 'fb' => '', - 'lastcontacted' => '', + 'objectID' => $resDataLine->ID, + 'objectType' => ZBS_TYPE_COMPANY, + 'grouped_by_source' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), - // Note Custom fields may be passed here, but will not have defaults so check isset() + ) + ); - // tags - 'tags' => -1, // pass an array of tag ids or tag strings - 'tag_mode' => 'replace', // replace|append|remove + } - 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) + // } - // allow this to be set for MS sync etc. - 'created' => -1, - 'lastupdated' => '', + // =================================================== + // ========== / #DB1LEGACY (TOMOVE) + // =================================================== - // obj links: - 'contacts' => false, // array of id's + $res[] = $resArr; - ), - - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) - // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + } + } - // this function as DAL1 func did. - 'extraMeta' => -1, - 'automatorPassthrough' => -1, - 'fallBackLog' => -1, + return $res; + } - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newCompany (because is migrating, not creating new :) this was -1 before + /** + * Returns a count of companies (owned) + * .. inc by status + * + * @return int count + */ + public function getCompanyCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'withStatus' => false, // will be str if used + + // permissions + 'ignoreowner' => true, // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - 'do_not_update_blanks' => false // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + $whereArr = array(); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - - // Needs this to grab custom fields (if passed) too :) - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ - - // only for data, limited fields below - if (is_array($data)) { - - if (isset($args['data'][$cK])) $data[$cK] = $args['data'][$cK]; - - } - - } - - // this takes limited fields + checks through for custom fields present - // (either as key zbsco_source or source, for example) - // then switches them into the $data array, for separate update - // where this'll fall over is if NO normal contact data is sent to update, just custom fields - if (is_array($limitedFields) && is_array($customFields)){ - - //$customFieldKeys = array_keys($customFields); - $newLimitedFields = array(); - - // cycle through - foreach ($limitedFields as $field){ - - // some weird case where getting empties, so added check - if (isset($field['key']) && !empty($field['key'])){ - - $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ( str_starts_with( $field['key'], 'zbsco_' ) ) { - $dePrefixed = substr( $field['key'], strlen( 'zbsco_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + if ( $withStatus !== false && ! empty( $withStatus ) ) { + $whereArr['status'] = array( 'zbsco_status', '=', '%s', $withStatus ); + } - if (isset($customFields[$field['key']])){ + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_COMPANY, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + } - // is custom, move to data - $data[$field['key']] = $field['val']; + /** + * adds or updates a company object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateCompany( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} Retrieve any cf + $customFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_COMPANY ) ); + $addrCustomFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'owner' => -1, + + // fields (directly) + 'data' => array( + + 'status' => '', + 'name' => '', + 'email' => '', + 'addr1' => '', + 'addr2' => '', + 'city' => '', + 'county' => '', + 'country' => '', + 'postcode' => '', + 'secaddr1' => '', + 'secaddr2' => '', + 'seccity' => '', + 'seccounty' => '', + 'seccountry' => '', + 'secpostcode' => '', + 'maintel' => '', + 'sectel' => '', + 'wpid' => '', + 'avatar' => '', + 'tw' => '', + 'li' => '', + 'fb' => '', + 'lastcontacted' => '', + + // Note Custom fields may be passed here, but will not have defaults so check isset() + + // tags + 'tags' => -1, // pass an array of tag ids or tag strings + 'tag_mode' => 'replace', // replace|append|remove + + 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) + + // allow this to be set for MS sync etc. + 'created' => -1, + 'lastupdated' => '', + + // obj links: + 'contacts' => false, // array of id's + + ), + + 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + + // this function as DAL1 func did. + 'extraMeta' => -1, + 'automatorPassthrough' => -1, + 'fallBackLog' => -1, + + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newCompany (because is migrating, not creating new :) this was -1 before + + 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } - } else if (!empty($dePrefixed) && isset($customFields[$dePrefixed])){ + // Needs this to grab custom fields (if passed) too :) + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { - // is custom, move to data - $data[$dePrefixed] = $field['val']; + // only for data, limited fields below + if ( is_array( $data ) ) { - } else { + if ( isset( $args['data'][ $cK ] ) ) { + $data[ $cK ] = $args['data'][ $cK ]; + } + } + } + } - // add it to limitedFields (it's not dealt with post-update) - $newLimitedFields[] = $field; - } + // this takes limited fields + checks through for custom fields present + // (either as key zbsco_source or source, for example) + // then switches them into the $data array, for separate update + // where this'll fall over is if NO normal contact data is sent to update, just custom fields + if ( is_array( $limitedFields ) && is_array( $customFields ) ) { - } + // $customFieldKeys = array_keys($customFields); + $newLimitedFields = array(); - } + // cycle through + foreach ( $limitedFields as $field ) { - // move this back in - $limitedFields = $newLimitedFields; - unset($newLimitedFields); + // some weird case where getting empties, so added check + if ( isset( $field['key'] ) && ! empty( $field['key'] ) ) { - } + $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( str_starts_with( $field['key'], 'zbsco_' ) ) { + $dePrefixed = substr( $field['key'], strlen( 'zbsco_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - #} =========== / LOAD ARGS ============ + if ( isset( $customFields[ $field['key'] ] ) ) { - #} ========== CHECK FIELDS ============ - - $id = (int)$id; - - // here we check that the potential owner CAN even own - if ($owner > 0 && !user_can($owner,'admin_zerobs_usr')) $owner = -1; + // is custom, move to data + $data[ $field['key'] ] = $field['val']; - // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } + } elseif ( ! empty( $dePrefixed ) && isset( $customFields[ $dePrefixed ] ) ) { + // is custom, move to data + $data[ $dePrefixed ] = $field['val']; - if (is_array($limitedFields)){ + } else { - // LIMITED UPDATE (only a few fields.) - if (!is_array($limitedFields) || count ($limitedFields) <= 0) return false; - // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; + // add it to limitedFields (it's not dealt with post-update) + $newLimitedFields[] = $field; + } + } + } - } else { + // move this back in + $limitedFields = $newLimitedFields; + unset( $newLimitedFields ); - // NORMAL, FULL UPDATE + } - // check email + load that user if present - if (!isset($data['email']) || empty($data['email'])){ + #} =========== / LOAD ARGS ============ - // no email - // Allow users without emails? WH removed this for db1->2 migration - // leaving this in breaks MIGRATIONS from DAL 1 - // in that those companies without emails will not be copied in - // return false; + #} ========== CHECK FIELDS ============ - } else { + $id = (int) $id; - // email present, check if it matches ID? - if (!empty($id) && $id > 0){ + // here we check that the potential owner CAN even own + if ( $owner > 0 && ! user_can( $owner, 'admin_zerobs_usr' ) ) { + $owner = -1; + } - // if ID + email, check if existing contact with email, (e.g. in use) - // ... allow it if the ID of that email contact matches the ID given here - // (else e.g. add email x to ID y without checking) - $potentialUSERID = (int)$this->getCompany(-1,array('email'=>$data['email'],'ignoreOwner'=>1,'onlyID'=>1)); - if (!empty($potentialUSERID) && $potentialUSERID > 0 && $id > 0 && $potentialUSERID != $id){ + // if owner = -1, add current + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); } - // email doesn't match ID - return false; - } + if ( is_array( $limitedFields ) ) { - // also check if has rights?!? Could be just email passed here + therefor got around owner check? hmm. + // LIMITED UPDATE (only a few fields.) + if ( ! is_array( $limitedFields ) || count( $limitedFields ) <= 0 ) { + return false; + } + // REQ. ID too (can only update) + if ( empty( $id ) || $id <= 0 ) { + return false; + } + } else { - } else { + // NORMAL, FULL UPDATE - // no ID, check if email present, and then update that co if so - $potentialUSERID = (int)$this->getCompany(-1,array('email'=>$data['email'],'ignoreOwner'=>1,'onlyID'=>1)); - if (isset($potentialUSERID) && !empty($potentialUSERID) && $potentialUSERID > 0) { $id = $potentialUSERID; } + // check email + load that user if present + if ( ! isset( $data['email'] ) || empty( $data['email'] ) ) { - } + // no email + // Allow users without emails? WH removed this for db1->2 migration + // leaving this in breaks MIGRATIONS from DAL 1 + // in that those companies without emails will not be copied in + // return false; + } else { - } + // email present, check if it matches ID? + if ( ! empty( $id ) && $id > 0 ) { - } + // if ID + email, check if existing contact with email, (e.g. in use) + // ... allow it if the ID of that email contact matches the ID given here + // (else e.g. add email x to ID y without checking) + $potentialUSERID = (int) $this->getCompany( + -1, + array( + 'email' => $data['email'], + 'ignoreOwner' => 1, + 'onlyID' => 1, + ) + ); + if ( ! empty( $potentialUSERID ) && $potentialUSERID > 0 && $id > 0 && $potentialUSERID != $id ) { + // email doesn't match ID + return false; + } - #} If no status, and default is specified in settings, add that in :) - if (is_null($data['status']) || !isset($data['status']) || empty($data['status'])){ + // also check if has rights?!? Could be just email passed here + therefor got around owner check? hmm. - // Default status for obj? -> this one gets for contacts -> $zbsCustomerMeta['status'] = zeroBSCRM_getSetting('defaultstatus'); + } else { - } + // no ID, check if email present, and then update that co if so + $potentialUSERID = (int) $this->getCompany( + -1, + array( + 'email' => $data['email'], + 'ignoreOwner' => 1, + 'onlyID' => 1, + ) + ); + if ( isset( $potentialUSERID ) && ! empty( $potentialUSERID ) && $potentialUSERID > 0 ) { + $id = $potentialUSERID; } + } + } + } - #} ========= / CHECK FIELDS =========== + #} If no status, and default is specified in settings, add that in :) + if ( $data['status'] === null || ! isset( $data['status'] ) || empty( $data['status'] ) ) { + // Default status for obj? -> this one gets for contacts -> $zbsCustomerMeta['status'] = zeroBSCRM_getSetting('defaultstatus'); - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== + } - // this only functions if externalsource is set (e.g. api/form, etc.) - if (isset($data['externalSources']) && is_array($data['externalSources']) && count($data['externalSources']) > 0) { - if (zeroBSCRM_getSetting('fieldoverride') == "1"){ + #} ========= / CHECK FIELDS =========== - $do_not_update_blanks = true; + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - } + // this only functions if externalsource is set (e.g. api/form, etc.) + if ( isset( $data['externalSources'] ) && is_array( $data['externalSources'] ) && count( $data['externalSources'] ) > 0 ) { + if ( zeroBSCRM_getSetting( 'fieldoverride' ) == '1' ) { - } + $do_not_update_blanks = true; - // either ext source + setting, or set by the func call - if ($do_not_update_blanks){ + } + } - // this setting says 'don't override filled-out data with blanks' - // so here we check through any passed blanks + convert to limitedFields - // only matters if $id is set (there is somt to update not add - if (isset($id) && !empty($id) && $id > 0){ + // either ext source + setting, or set by the func call + if ( $do_not_update_blanks ) { - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_company($data); - //unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue - //unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) + // this setting says 'don't override filled-out data with blanks' + // so here we check through any passed blanks + convert to limitedFields + // only matters if $id is set (there is somt to update not add + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - $origData = $data; //$data = array(); - $limitedData = array(); // array(array('key'=>'zbsco_x','val'=>y,'type'=>'%s')) + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_company( $data ); + // unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue + // unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) - // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates - foreach ($dbData as $k => $v){ + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbsco_x','val'=>y,'type'=>'%s')) - $intV = (int)$v; + // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) + // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates + foreach ( $dbData as $k => $v ) { - // only add if valuenot empty - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ + $intV = (int) $v; - // add to update arr - $limitedData[] = array( - 'key' => 'zbsco_'.$k, // we have to add zbsco_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbsco_'.$k) - ); + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { - // add to remade $data for post-update updates - $data[$k] = $v; + // add to update arr + $limitedData[] = array( + 'key' => 'zbsco_' . $k, // we have to add zbsco_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbsco_' . $k ), + ); - } + // add to remade $data for post-update updates + $data[ $k ] = $v; - } + } + } - // copy over - $limitedFields = $limitedData; + // copy over + $limitedFields = $limitedData; - } // / if ID + } // / if ID - } // / if do_not_update_blanks + } // / if do_not_update_blanks - #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== + #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== + #} ========= BUILD DATA =========== - #} ========= BUILD DATA =========== + $update = false; + $dataArr = array(); + $typeArr = array(); - $update = false; $dataArr = array(); $typeArr = array(); + if ( is_array( $limitedFields ) ) { - if (is_array($limitedFields)){ + // LIMITED FIELDS + $update = true; - // LIMITED FIELDS - $update = true; + // cycle through + foreach ( $limitedFields as $field ) { - // cycle through - foreach ($limitedFields as $field){ + // some weird case where getting empties, so added check + if ( ! empty( $field['key'] ) ) { + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } + } - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } + // add update time + if ( ! isset( $dataArr['zbsco_lastupdated'] ) ) { + $dataArr['zbsco_lastupdated'] = time(); + $typeArr[] = '%d'; } + } else { - } + // FULL UPDATE/INSERT - // add update time - if (!isset($dataArr['zbsco_lastupdated'])){ $dataArr['zbsco_lastupdated'] = time(); $typeArr[] = '%d'; } + // contacts - avoid dupes + if ( isset( $data['contacts'] ) && is_array( $data['contacts'] ) ) { - } else { + $coArr = array(); + foreach ( $data['contacts'] as $c ) { + $cI = (int) $c; + if ( $cI > 0 && ! in_array( $cI, $coArr ) ) { + $coArr[] = $cI; + } + } - // FULL UPDATE/INSERT + // reset the main + if ( count( $coArr ) > 0 ) { + $data['contacts'] = $coArr; + } else { + $data['contacts'] = 'unset'; + } + unset( $coArr ); - // contacts - avoid dupes - if (isset($data['contacts']) && is_array($data['contacts'])){ + } - $coArr = array(); - foreach ($data['contacts'] as $c){ - $cI = (int)$c; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; - } + // UPDATE + $dataArr = array( + + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, + + 'zbsco_status' => $data['status'], + 'zbsco_name' => $data['name'], + 'zbsco_email' => $data['email'], + 'zbsco_addr1' => $data['addr1'], + 'zbsco_addr2' => $data['addr2'], + 'zbsco_city' => $data['city'], + 'zbsco_county' => $data['county'], + 'zbsco_country' => $data['country'], + 'zbsco_postcode' => $data['postcode'], + 'zbsco_secaddr1' => $data['secaddr1'], + 'zbsco_secaddr2' => $data['secaddr2'], + 'zbsco_seccity' => $data['seccity'], + 'zbsco_seccounty' => $data['seccounty'], + 'zbsco_seccountry' => $data['seccountry'], + 'zbsco_secpostcode' => $data['secpostcode'], + 'zbsco_maintel' => $data['maintel'], + 'zbsco_sectel' => $data['sectel'], + 'zbsco_wpid' => $data['wpid'], + 'zbsco_avatar' => $data['avatar'], + 'zbsco_tw' => $data['tw'], + 'zbsco_li' => $data['li'], + 'zbsco_fb' => $data['fb'], + 'zbsco_lastupdated' => time(), + 'zbsco_lastcontacted' => $data['lastcontacted'], + + ); + + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner + + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%d', + '%s', + '%s', + '%s', + '%s', + '%d', + '%d', + + ); + + if ( ! empty( $id ) && $id > 0 ) { + + // is update + $update = true; + + // got owner change? - allow all basically? + if ( isset( $owner ) && $owner > 0 ) { + + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; - // reset the main - if (count($coArr) > 0) - $data['contacts'] = $coArr; - else - $data['contacts'] = 'unset'; - unset($coArr); + } + } else { + + // INSERT (get's few extra :D) + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbsco_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbsco_created'] = time(); + $typeArr[] = '%d'; + } + } + } - } + #} ========= / BUILD DATA =========== - // UPDATE - $dataArr = array( + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, - - 'zbsco_status' => $data['status'], - 'zbsco_name' => $data['name'], - 'zbsco_email' => $data['email'], - 'zbsco_addr1' => $data['addr1'], - 'zbsco_addr2' => $data['addr2'], - 'zbsco_city' => $data['city'], - 'zbsco_county' => $data['county'], - 'zbsco_country' => $data['country'], - 'zbsco_postcode' => $data['postcode'], - 'zbsco_secaddr1' => $data['secaddr1'], - 'zbsco_secaddr2' => $data['secaddr2'], - 'zbsco_seccity' => $data['seccity'], - 'zbsco_seccounty' => $data['seccounty'], - 'zbsco_seccountry' => $data['seccountry'], - 'zbsco_secpostcode' => $data['secpostcode'], - 'zbsco_maintel' => $data['maintel'], - 'zbsco_sectel' => $data['sectel'], - 'zbsco_wpid' => $data['wpid'], - 'zbsco_avatar' => $data['avatar'], - 'zbsco_tw' => $data['tw'], - 'zbsco_li' => $data['li'], - 'zbsco_fb' => $data['fb'], - 'zbsco_lastupdated' => time(), - 'zbsco_lastcontacted' =>$data['lastcontacted'], - - ); - - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner - - - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%d', - '%s', - '%s', - '%s', - '%s', - '%d', - '%d', - - ); - - if (!empty($id) && $id > 0){ - - // is update - $update = true; - - // got owner change? - allow all basically? - if (isset($owner) && $owner > 0){ - - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - - } - - } else { - - // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $typeArr[] = '%d'; - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbsco_created'] = $data['created'];$typeArr[] = '%d'; - } else { - $dataArr['zbsco_created'] = time(); $typeArr[] = '%d'; - } - - } - - } - - #} ========= / BUILD DATA =========== - - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== - - // if we're passing limitedFields we skip these, for now - // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ - - // verify uniques - if (!$this->verifyUniqueValues($data,$id)) return false; // / fails unique field verify - - // verify not_empty - if (!$this->verifyNonEmptyValues($data)) return false; // / fails empty field verify - - } - - // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks($dataArr); - - #} ========= / CHECK force_uniques & not_empty ================ - #} ============================================================ - - #} Check if ID present - if ($update){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - $originalStatus = $this->getCompanyStatus($id); - - $previous_company_obj = $this->getCompany( $id ); - - // log any change of status - if (isset($dataArr['zbsco_status']) && !empty($dataArr['zbsco_status']) && !empty($originalStatus) && $dataArr['zbsco_status'] != $originalStatus){ - - // status change - $statusChange = array( - 'from' => $originalStatus, - 'to' => $dataArr['zbsco_status'] - ); - } - - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['companies'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ - - - // if passing limitedFields instead of data, we ignore the following - // this doesn't work, because data is in args default as arr - //if (isset($data) && is_array($data)){ - // so... - if (!isset($limitedFields) || !is_array($limitedFields) || $limitedFields == -1){ - - // OBJ LINKS - contacts -> companies - // This would link Company -> Contacts, $this->addUpdateObjectLinks($id,$data['contacts'],ZBS_TYPE_CONTACT); - // ... but we need it Contacts -> Company, so use a direct call in this case: - if (is_array($data['contacts'])) foreach ($data['contacts'] as $contactID){ - - // if is ID - if ($contactID > 0){ - - // append to it's links (in case it has other companies too) - $this->DAL()->addUpdateObjLinks(array( - 'objtypefrom' => ZBS_TYPE_CONTACT, - 'objtypeto' => ZBS_TYPE_COMPANY, - 'objfromid' => $contactID, - 'objtoids' => array($id), - 'mode' => 'append')); - - } - - } - - // tags - if (isset($data['tags']) && is_array($data['tags'])) { - - $this->addUpdateCompanyTags( - array( - 'id' => $id, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); - - } - - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( - array( - 'obj_id' => $id, - 'obj_type_id' => ZBS_TYPE_COMPANY, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), - ) - ); // for IA below - - // Custom fields? - - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ - - // any? - if (isset($data[$cK])){ - - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $id, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); - - } - - } - - // Also got to catch any 'addr' custom fields :) - if (is_array($addrCustomFields) && count($addrCustomFields) > 0){ - - // cycle through addr custom fields + save - // see #ZBS-518, not easy until addr's get DAL2 - // WH deferring here - - // WH later added via the addUpdateContactField method - should work fine if we catch properly in get - foreach ($addrCustomFields as $cK => $cF){ - - // v2: - //$cKN = (int)$cK+1; - //$cKey = 'addr_cf'.$cKN; - //$cKey2 = 'secaddr_cf'.$cKN; - // v3: - $cKey = 'addr_'.$cK; - $cKey2 = 'secaddr_'.$cK; - - // any? - if (isset($data[$cKey])){ - - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $id, - 'objkey' => $cKey, - 'objval' => $data[$cKey] - ))); - - } - - // any? - if (isset($data[$cKey2])){ - - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $id, - 'objkey' => $cKey2, - 'objval' => $data[$cKey2] - ))); + // if we're passing limitedFields we skip these, for now + // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 + if ( ! is_array( $limitedFields ) ) { - } + // verify uniques + if ( ! $this->verifyUniqueValues( $data, $id ) ) { + return false; // / fails unique field verify + } - } + // verify not_empty + if ( ! $this->verifyNonEmptyValues( $data ) ) { + return false; // / fails empty field verify + } + } + // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections + $dataArr = $this->wpdbChecks( $dataArr ); - } + #} ========= / CHECK force_uniques & not_empty ================ + #} ============================================================ - // / Custom Fields + #} Check if ID present + if ( $update ) { - } // / if $data + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) + $originalStatus = $this->getCompanyStatus( $id ); - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $previous_company_obj = $this->getCompany( $id ); - $confirmedExtraMeta = array(); + // log any change of status + if ( isset( $dataArr['zbsco_status'] ) && ! empty( $dataArr['zbsco_status'] ) && ! empty( $originalStatus ) && $dataArr['zbsco_status'] != $originalStatus ) { - foreach ($extraMeta as $k => $v){ + // status change + $statusChange = array( + 'from' => $originalStatus, + 'to' => $dataArr['zbsco_status'], + ); + } - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['companies'], + $dataArr, + array( // where + 'ID' => $id, + ), + $typeArr, + array( // where data types + '%d', + ) + ) !== false ) { + + // if passing limitedFields instead of data, we ignore the following + // this doesn't work, because data is in args default as arr + // if (isset($data) && is_array($data)){ + // so... + if ( ! isset( $limitedFields ) || ! is_array( $limitedFields ) || $limitedFields == -1 ) { + + // OBJ LINKS - contacts -> companies + // This would link Company -> Contacts, $this->addUpdateObjectLinks($id,$data['contacts'],ZBS_TYPE_CONTACT); + // ... but we need it Contacts -> Company, so use a direct call in this case: + if ( is_array( $data['contacts'] ) ) { + foreach ( $data['contacts'] as $contactID ) { + + // if is ID + if ( $contactID > 0 ) { + + // append to it's links (in case it has other companies too) + $this->DAL()->addUpdateObjLinks( + array( + 'objtypefrom' => ZBS_TYPE_CONTACT, + 'objtypeto' => ZBS_TYPE_COMPANY, + 'objfromid' => $contactID, + 'objtoids' => array( $id ), + 'mode' => 'append', + ) + ); + + } + } + } - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_COMPANY,$id,'extra_'.$cleanKey,$v); + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + $this->addUpdateCompanyTags( + array( + 'id' => $id, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); - } + } - } + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $id, + 'obj_type_id' => ZBS_TYPE_COMPANY, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below + // Custom fields? - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ - - #} FALLBACK - #} (This fires for customers that weren't added because they already exist.) - #} e.g. x@g.com exists, so add log "x@g.com filled out form" - #} Requires a type and a shortdesc - if ( - is_array( $fallBackLog ) && ! empty( $fallBackLog['type'] ) && ! empty( $fallBackLog['shortdesc'] ) // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - ){ + #} Cycle through + add/update if set + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { - #} Brutal add, maybe validate more?! + // any? + if ( isset( $data[ $cK ] ) ) { - #} Long desc if present: - $zbsNoteLongDesc = ''; if (isset($fallBackLog['longdesc']) && !empty($fallBackLog['longdesc'])) $zbsNoteLongDesc = $fallBackLog['longdesc']; + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $id, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); - #} Only raw checked... but proceed. - zeroBS_addUpdateObjLog( - ZBS_TYPE_COMPANY, - $id, - -1, - -1, - array( - // Anything here will get wrapped into an array and added as the meta vals - 'type' => $fallBackLog['type'], // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - 'shortdesc' => $fallBackLog['shortdesc'], // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - 'longdesc' => $zbsNoteLongDesc, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - ) - ); - - - } - - // catch dirty flag (update of status) (note, after update_post_meta - as separate) - //if (isset($_POST['zbsco_status_dirtyflag']) && $_POST['zbsco_status_dirtyflag'] == "1"){ - // actually here, it's set above - if (isset($statusChange) && is_array($statusChange)){ + } + } + } - // status has changed + // Also got to catch any 'addr' custom fields :) + if ( is_array( $addrCustomFields ) && count( $addrCustomFields ) > 0 ) { - // IA - zeroBSCRM_FireInternalAutomator('company.status.update',array( - 'id'=>$id, - 'againstid' => $id, - 'data'=> $dataArr, - 'from' => $statusChange['from'], - 'to' => $statusChange['to'] - )); + // cycle through addr custom fields + save + // see #ZBS-518, not easy until addr's get DAL2 + // WH deferring here - } + // WH later added via the addUpdateContactField method - should work fine if we catch properly in get + foreach ( $addrCustomFields as $cK => $cF ) { + // v2: + // $cKN = (int)$cK+1; + // $cKey = 'addr_cf'.$cKN; + // $cKey2 = 'secaddr_cf'.$cKN; + // v3: + $cKey = 'addr_' . $cK; + $cKey2 = 'secaddr_' . $cK; - // IA General company update (2.87+) - zeroBSCRM_FireInternalAutomator('company.update',array( - 'id'=>$id, - 'againstid' => $id, - 'data' => $dataArr, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - 'prev_company' => $previous_company_obj, - )); + // any? + if ( isset( $data[ $cKey ] ) ) { - + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $id, + 'objkey' => $cKey, + 'objval' => $data[ $cKey ], + ), + ) + ); - } + } - - // Successfully updated - Return id - return $id; + // any? + if ( isset( $data[ $cKey2 ] ) ) { - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); - - // FAILED update - return false; - - } + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $id, + 'objkey' => $cKey2, + 'objval' => $data[ $cKey2 ], + ), + ) + ); - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['companies'], - $dataArr, - $typeArr ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - - - // OBJ LINKS - contacts -> companies - // This would link Company -> Contacts, $this->addUpdateObjectLinks($newID,$data['contacts'],ZBS_TYPE_CONTACT); - // ... but we need it Contacts -> Company, so use a direct call in this case: - if (is_array($data['contacts'])) foreach ($data['contacts'] as $contactID){ - - // if is ID - if ($contactID > 0){ - - // append to it's links (in case it has other companies too) - $this->DAL()->addUpdateObjLinks(array( - 'objtypefrom' => ZBS_TYPE_CONTACT, - 'objtypeto' => ZBS_TYPE_COMPANY, - 'objfromid' => $contactID, - 'objtoids' => array($newID), - 'mode' => 'append')); - - } + } + } + } - } + // / Custom Fields - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + } // / if $data - $this->addUpdateCompanyTags( - array( - 'id' => $newID, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } + $confirmedExtraMeta = array(); - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( - array( - 'obj_id' => $newID, - 'obj_type_id' => ZBS_TYPE_COMPANY, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), - ) - ); // for IA below + foreach ( $extraMeta as $k => $v ) { - // Custom fields? + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_COMPANY, $id, 'extra_' . $cleanKey, $v ); - // any? - if (isset($data[$cK])){ + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $newID, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + } + } - } + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // UPDATING CONTACT + if ( ! $silentInsert ) { - } + #} FALLBACK + #} (This fires for customers that weren't added because they already exist.) + #} e.g. x@g.com exists, so add log "x@g.com filled out form" + #} Requires a type and a shortdesc + if ( + is_array( $fallBackLog ) && ! empty( $fallBackLog['type'] ) && ! empty( $fallBackLog['shortdesc'] ) // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + ) { - // / Custom Fields - + #} Brutal add, maybe validate more?! - // Also got to catch any 'addr' custom fields :) - if (is_array($addrCustomFields) && count($addrCustomFields) > 0){ + #} Long desc if present: + $zbsNoteLongDesc = ''; + if ( isset( $fallBackLog['longdesc'] ) && ! empty( $fallBackLog['longdesc'] ) ) { + $zbsNoteLongDesc = $fallBackLog['longdesc']; + } - foreach ($addrCustomFields as $cK => $cF){ + #} Only raw checked... but proceed. + zeroBS_addUpdateObjLog( + ZBS_TYPE_COMPANY, + $id, + -1, + -1, + array( + // Anything here will get wrapped into an array and added as the meta vals + 'type' => $fallBackLog['type'], // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + 'shortdesc' => $fallBackLog['shortdesc'], // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + 'longdesc' => $zbsNoteLongDesc, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + ) + ); + + } + + // catch dirty flag (update of status) (note, after update_post_meta - as separate) + // if (isset($_POST['zbsco_status_dirtyflag']) && $_POST['zbsco_status_dirtyflag'] == "1"){ + // actually here, it's set above + if ( isset( $statusChange ) && is_array( $statusChange ) ) { + + // status has changed + + // IA + zeroBSCRM_FireInternalAutomator( + 'company.status.update', + array( + 'id' => $id, + 'againstid' => $id, + 'data' => $dataArr, + 'from' => $statusChange['from'], + 'to' => $statusChange['to'], + ) + ); + + } + + // IA General company update (2.87+) + zeroBSCRM_FireInternalAutomator( + 'company.update', + array( + 'id' => $id, + 'againstid' => $id, + 'data' => $dataArr, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + 'prev_company' => $previous_company_obj, + ) + ); + + } + + // Successfully updated - Return id + return $id; + + } else { + + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); + + // FAILED update + return false; - $cKey = 'addr_'.$cK; - $cKey2 = 'secaddr_'.$cK; + } + } else { - if (isset($data[$cKey])){ + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['companies'], + $dataArr, + $typeArr + ) > 0 ) { - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $newID, - 'objkey' => $cKey, - 'objval' => $data[$cKey] - ))); + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - } + // OBJ LINKS - contacts -> companies + // This would link Company -> Contacts, $this->addUpdateObjectLinks($newID,$data['contacts'],ZBS_TYPE_CONTACT); + // ... but we need it Contacts -> Company, so use a direct call in this case: + if ( is_array( $data['contacts'] ) ) { + foreach ( $data['contacts'] as $contactID ) { - // any? - if (isset($data[$cKey2])){ + // if is ID + if ( $contactID > 0 ) { - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $newID, - 'objkey' => $cKey2, - 'objval' => $data[$cKey2] - ))); + // append to it's links (in case it has other companies too) + $this->DAL()->addUpdateObjLinks( + array( + 'objtypefrom' => ZBS_TYPE_CONTACT, + 'objtypeto' => ZBS_TYPE_COMPANY, + 'objfromid' => $contactID, + 'objtoids' => array( $newID ), + 'mode' => 'append', + ) + ); - } + } + } + } + + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { + + $this->addUpdateCompanyTags( + array( + 'id' => $newID, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); + + } + + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $newID, + 'obj_type_id' => ZBS_TYPE_COMPANY, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below + + // Custom fields? + + #} Cycle through + add/update if set + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { + + // any? + if ( isset( $data[ $cK ] ) ) { + + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $newID, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); - } + } + } + } + // / Custom Fields - } + // Also got to catch any 'addr' custom fields :) + if ( is_array( $addrCustomFields ) && count( $addrCustomFields ) > 0 ) { - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + foreach ( $addrCustomFields as $cK => $cF ) { - $confirmedExtraMeta = array(); + $cKey = 'addr_' . $cK; + $cKey2 = 'secaddr_' . $cK; - foreach ($extraMeta as $k => $v){ + if ( isset( $data[ $cKey ] ) ) { - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $newID, + 'objkey' => $cKey, + 'objval' => $data[ $cKey ], + ), + ) + ); - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_COMPANY,$newID,'extra_'.$cleanKey,$v); + } - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + // any? + if ( isset( $data[ $cKey2 ] ) ) { + + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $newID, + 'objkey' => $cKey2, + 'objval' => $data[ $cKey2 ], + ), + ) + ); - } + } + } + } - } + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $confirmedExtraMeta = array(); + foreach ( $extraMeta as $k => $v ) { - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT - if (!$silentInsert){ + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - #} Add to automator - zeroBSCRM_FireInternalAutomator('company.new',array( - 'id'=>$newID, - 'data'=>$dataArr, - 'extsource'=>$approvedExternalSource, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_COMPANY, $newID, 'extra_' . $cleanKey, $v ); - } - - return $newID; + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); + } + } - #} Failed to Insert - return false; + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // NEW CONTACT + if ( ! $silentInsert ) { - } + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'company.new', + array( + 'id' => $newID, + 'data' => $dataArr, + 'extsource' => $approvedExternalSource, + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); - } + } - return false; + return $newID; - } + } else { - /** - * adds or updates a company's tags - * ... this is really just a wrapper for addUpdateObjectTags - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateCompanyTags($args=array()){ + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); - global $ZBSCRM_t,$wpdb; + #} Failed to Insert + return false; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } + } - 'id' => -1, // co id - - // generic pass-through (array of tag strings or tag IDs): - 'tag_input' => -1, + return false; + } - // or either specific: - 'tagIDs' => -1, - 'tags' => -1, + /** + * adds or updates a company's tags + * ... this is really just a wrapper for addUpdateObjectTags + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateCompanyTags( $args = array() ) { - 'mode' => 'append' + global $ZBSCRM_t, $wpdb; - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} ============ LOAD ARGS ============= + $defaultArgs = array( - #} ========== CHECK FIELDS ============ + 'id' => -1, // co id - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; + // generic pass-through (array of tag strings or tag IDs): + 'tag_input' => -1, - #} ========= / CHECK FIELDS =========== + // or either specific: + 'tagIDs' => -1, + 'tags' => -1, - return $this->DAL()->addUpdateObjectTags( - array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $id, - 'tag_input' => $tag_input, - 'tags' => $tags, - 'tagIDs' => $tagIDs, - 'mode' => $mode - ) - ); + 'mode' => 'append', - } - - - - /** - * deletes a company object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteCompany($args=array()){ - - global $ZBSCRM_t,$wpdb,$zbs; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - 'saveOrphans' => true - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ - - // delete any tag links - $this->DAL()->deleteTagObjLinks(array( - - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $id - )); - - // delete any external source information - $this->DAL()->delete_external_sources( array( - - 'obj_type' => ZBS_TYPE_COMPANY, - 'obj_id' => $id, - 'obj_source' => 'all', - - )); - } - - $del = zeroBSCRM_db2_deleteGeneric($id,'companies'); - - #} Add to automator - zeroBSCRM_FireInternalAutomator('company.delete',array( - 'id'=>$id, - 'saveOrphans'=>$saveOrphans - )); - - return $del; - - } - - return false; - - } - - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array company (clean obj) - */ - private function tidy_company($obj=false,$withCustomFields=false){ - - $res = false; - - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = $obj->zbs_owner; - - $res['status'] = $this->stripSlashes($obj->zbsco_status); - $res['name'] = $this->stripSlashes($obj->zbsco_name); - $res['email'] = $this->stripSlashes($obj->zbsco_email); - $res['addr1'] = $this->stripSlashes($obj->zbsco_addr1); - $res['addr2'] = $this->stripSlashes($obj->zbsco_addr2); - $res['city'] = $this->stripSlashes($obj->zbsco_city); - $res['county'] = $this->stripSlashes($obj->zbsco_county); - $res['country'] = $this->stripSlashes($obj->zbsco_country); - $res['postcode'] = $this->stripSlashes($obj->zbsco_postcode); - $res['secaddr1'] = $this->stripSlashes($obj->zbsco_secaddr1); - $res['secaddr2'] = $this->stripSlashes($obj->zbsco_secaddr2); - $res['seccity'] = $this->stripSlashes($obj->zbsco_seccity); - $res['seccounty'] = $this->stripSlashes($obj->zbsco_seccounty); - $res['seccountry'] = $this->stripSlashes($obj->zbsco_seccountry); - $res['secpostcode'] = $this->stripSlashes($obj->zbsco_secpostcode); - $res['maintel'] = $this->stripSlashes($obj->zbsco_maintel); - $res['sectel'] = $this->stripSlashes($obj->zbsco_sectel); - $res['wpid'] = (int)$obj->zbsco_wpid; - $res['avatar'] = $this->stripSlashes($obj->zbsco_avatar); - $res['tw'] = $this->stripSlashes($obj->zbsco_tw); - $res['li'] = $this->stripSlashes($obj->zbsco_li); - $res['fb'] = $this->stripSlashes($obj->zbsco_fb); - $res['created'] = (int)$obj->zbsco_created; - $res['created_date'] = (isset($obj->zbsco_created) && $obj->zbsco_created > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsco_created,false,true) : false; - $res['lastupdated'] = (int)$obj->zbsco_lastupdated; - $res['lastupdated_date'] = (isset($obj->zbsco_lastupdated) && $obj->zbsco_lastupdated > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsco_lastupdated,false,true) : false; - $res['lastcontacted'] = (int)$obj->zbsco_lastcontacted; - $res['lastcontacted_date'] = (isset($obj->zbsco_lastcontacted) && $obj->zbsco_lastcontacted > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsco_lastcontacted,false,true) : false; - - - // if have totals, pass them :) - if (isset($obj->quotes_total)) $res['quotes_total'] = $obj->quotes_total; - if ( isset( $obj->invoices_total ) ) { - $res['invoices_total'] = $obj->invoices_total; - $res['invoices_total_inc_deleted'] = $obj->invoices_total_inc_deleted; - $res['invoices_count'] = $obj->invoices_count; - $res['invoices_count_inc_deleted'] = $obj->invoices_count_inc_deleted; - } - if ( isset( $obj->transactions_total ) ) { - $res['transactions_total'] = $obj->transactions_total; + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } } - if (isset($obj->transactions_paid_total)) $res['transactions_paid_total'] = $obj->transactions_paid_total; - - // and if have invs + trans totals, add to make total val - // This now accounts for "part payments" where trans are part/whole payments against invs - if (isset($res['invoices_total']) || isset($res['transactions_total'])){ - $res['total_value'] = jpcrm_get_total_value_from_contact_or_company( $res ); - } - - // custom fields - tidy any that are present: - if ($withCustomFields) $res = $this->tidyAddCustomFields(ZBS_TYPE_COMPANY,$obj,$res,true); + } + #} =========== / LOAD ARGS ============ - } + #} ========== CHECK FIELDS ============ + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } - return $res; + #} ========= / CHECK FIELDS =========== + + return $this->DAL()->addUpdateObjectTags( + array( + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $id, + 'tag_input' => $tag_input, + 'tags' => $tags, + 'tagIDs' => $tagIDs, + 'mode' => $mode, + ) + ); + } + /** + * deletes a company object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteCompany( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'saveOrphans' => true, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - } + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + // delete orphans? + if ( $saveOrphans === false ) { - /** - * Wrapper, use $this->getCompanyMeta($contactID,$key) for easy retrieval of singular company - * Simplifies $this->getMeta - * - * @param int objtype - * @param int objid - * @param string key - * - * @return array company meta result - */ - public function getCompanyMeta($id=-1,$key='',$default=false){ + // delete any tag links + $this->DAL()->deleteTagObjLinks( + array( - global $zbs; + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $id, + ) + ); - if (!empty($key)){ + // delete any external source information + $this->DAL()->delete_external_sources( + array( - return $this->DAL()->getMeta(array( + 'obj_type' => ZBS_TYPE_COMPANY, + 'obj_id' => $id, + 'obj_source' => 'all', - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $id, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default, - 'ignoreowner' => true // for now !! + ) + ); + } - )); + $del = zeroBSCRM_db2_deleteGeneric( $id, 'companies' ); - } + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'company.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); - return $default; - } + return $del; + } - /** - * Returns an email addr against a Company - * - * @param int id Company ID - * - * @return string Company email - */ - public function getCompanyEmail($id=-1){ + return false; + } - global $zbs; + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array company (clean obj) + */ + private function tidy_company( $obj = false, $withCustomFields = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = $obj->zbs_owner; + + $res['status'] = $this->stripSlashes( $obj->zbsco_status ); + $res['name'] = $this->stripSlashes( $obj->zbsco_name ); + $res['email'] = $this->stripSlashes( $obj->zbsco_email ); + $res['addr1'] = $this->stripSlashes( $obj->zbsco_addr1 ); + $res['addr2'] = $this->stripSlashes( $obj->zbsco_addr2 ); + $res['city'] = $this->stripSlashes( $obj->zbsco_city ); + $res['county'] = $this->stripSlashes( $obj->zbsco_county ); + $res['country'] = $this->stripSlashes( $obj->zbsco_country ); + $res['postcode'] = $this->stripSlashes( $obj->zbsco_postcode ); + $res['secaddr1'] = $this->stripSlashes( $obj->zbsco_secaddr1 ); + $res['secaddr2'] = $this->stripSlashes( $obj->zbsco_secaddr2 ); + $res['seccity'] = $this->stripSlashes( $obj->zbsco_seccity ); + $res['seccounty'] = $this->stripSlashes( $obj->zbsco_seccounty ); + $res['seccountry'] = $this->stripSlashes( $obj->zbsco_seccountry ); + $res['secpostcode'] = $this->stripSlashes( $obj->zbsco_secpostcode ); + $res['maintel'] = $this->stripSlashes( $obj->zbsco_maintel ); + $res['sectel'] = $this->stripSlashes( $obj->zbsco_sectel ); + $res['wpid'] = (int) $obj->zbsco_wpid; + $res['avatar'] = $this->stripSlashes( $obj->zbsco_avatar ); + $res['tw'] = $this->stripSlashes( $obj->zbsco_tw ); + $res['li'] = $this->stripSlashes( $obj->zbsco_li ); + $res['fb'] = $this->stripSlashes( $obj->zbsco_fb ); + $res['created'] = (int) $obj->zbsco_created; + $res['created_date'] = ( isset( $obj->zbsco_created ) && $obj->zbsco_created > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsco_created, false, true ) : false; + $res['lastupdated'] = (int) $obj->zbsco_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbsco_lastupdated ) && $obj->zbsco_lastupdated > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsco_lastupdated, false, true ) : false; + $res['lastcontacted'] = (int) $obj->zbsco_lastcontacted; + $res['lastcontacted_date'] = ( isset( $obj->zbsco_lastcontacted ) && $obj->zbsco_lastcontacted > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsco_lastcontacted, false, true ) : false; + + // if have totals, pass them :) + if ( isset( $obj->quotes_total ) ) { + $res['quotes_total'] = $obj->quotes_total; + } + if ( isset( $obj->invoices_total ) ) { + $res['invoices_total'] = $obj->invoices_total; + $res['invoices_total_inc_deleted'] = $obj->invoices_total_inc_deleted; + $res['invoices_count'] = $obj->invoices_count; + $res['invoices_count_inc_deleted'] = $obj->invoices_count_inc_deleted; + } + if ( isset( $obj->transactions_total ) ) { + $res['transactions_total'] = $obj->transactions_total; + } + if ( isset( $obj->transactions_paid_total ) ) { + $res['transactions_paid_total'] = $obj->transactions_paid_total; + } - $id = (int)$id; + // and if have invs + trans totals, add to make total val + // This now accounts for "part payments" where trans are part/whole payments against invs + if ( isset( $res['invoices_total'] ) || isset( $res['transactions_total'] ) ) { + $res['total_value'] = jpcrm_get_total_value_from_contact_or_company( $res ); + } - if ($id > 0){ + // custom fields - tidy any that are present: + if ( $withCustomFields ) { + $res = $this->tidyAddCustomFields( ZBS_TYPE_COMPANY, $obj, $res, true ); + } + } - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_COMPANY, - 'colname' => 'zbsco_email', - 'ignoreowner' => true)); + return $res; + } - } + /** + * Wrapper, use $this->getCompanyMeta($contactID,$key) for easy retrieval of singular company + * Simplifies $this->getMeta + * + * @param int objtype + * @param int objid + * @param string key + * + * @return array company meta result + */ + public function getCompanyMeta( $id = -1, $key = '', $default = false ) { - return false; - - } - - /** - * Returns an ownerid against a company - * - * @param int id company ID - * - * @return int company owner id - */ - public function getCompanyOwner($id=-1){ + global $zbs; - global $zbs; + if ( ! empty( $key ) ) { - $id = (int)$id; + return $this->DAL()->getMeta( + array( - if ($id > 0){ + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $id, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, + 'ignoreowner' => true, // for now !! - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_COMPANY, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); + ) + ); - } + } - return false; - - } + return $default; + } /** - * Returns an status against a company + * Returns an email addr against a Company * - * @param int $id company ID. + * @param int id Company ID * - * @return string company status string + * @return string Company email */ - public function getCompanyStatus($id=-1){ - - global $zbs; - - $id = (int)$id; + public function getCompanyEmail( $id = -1 ) { - if ($id > 0){ + global $zbs; - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_COMPANY, - 'colname' => 'zbsco_status', - 'ignoreowner'=>true)); + $id = (int) $id; - } + if ( $id > 0 ) { - return false; - - } + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_COMPANY, + 'colname' => 'zbsco_email', + 'ignoreowner' => true, + ) + ); - /** - * Returns a formatted fullname (optionally including ID + first line of addr) - * Replaces zeroBS_companyName - * - * @param int id Company ID - * @param array Company array (if already loaded can pass) - * @param array args (see format_fullname func) - * - * @return string Company full name - */ - public function getCompanyNameEtc($id=-1,$companyArr=false,$args=array()){ + } - global $zbs; + return false; + } - $id = (int)$id; + /** + * Returns an ownerid against a company + * + * @param int id company ID + * + * @return int company owner id + */ + public function getCompanyOwner( $id = -1 ) { - // this makes sure it uses name not 'fname' - $args['company'] = true; + global $zbs; - if ($id > 0){ + $id = (int) $id; - // get a limited-fields contact obj - $company = $zbs->DAL->companies->getCompany($id,array('withCustomFields' => false,'fields'=>array('zbsco_addr1','zbsco_name'),'ignoreowner' => true)); - if (isset($company) && is_array($company) && isset($company['name'])) - return $this->format_name_etc($company,$args); + if ( $id > 0 ) { - } elseif (is_array($companyArr)){ + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_COMPANY, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); - // pass through - return $this->format_name_etc($companyArr,$args); + } - } + return false; + } - return false; - - } + /** + * Returns an status against a company + * + * @param int $id company ID. + * + * @return string company status string + */ + public function getCompanyStatus( $id = -1 ) { - /** - * Returns a formatted address of a contact - * Replaces zeroBS_companyAddr - * - * @param int id Company ID - * @param array Company array (if already loaded can pass) - * @param array args (see format_address func) - * - * @return string Company addr html - */ - public function getCompanyAddress($id=-1,$companyArr=false,$args=array()){ + global $zbs; - global $zbs; + $id = (int) $id; - $id = (int)$id; + if ( $id > 0 ) { - if ($id > 0){ + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_COMPANY, + 'colname' => 'zbsco_status', + 'ignoreowner' => true, + ) + ); - // get a limited-fields company obj - // this is hacky, but basically get whole basic company record for this for now, because - // this doesn't properly get addr custom fields: - // $company = $this->getContact($id,array('withCustomFields' => false,'fields'=>$this->field_list_address2,'ignoreowner'=>true)); - $company = $this->getCompany($id,array('withCustomFields' => true,'ignoreowner'=>true)); - if (isset($company) && is_array($company) && isset($company['addr1'])) - return $this->format_address($company,$args); + } - } elseif (is_array($companyArr)){ + return false; + } - // pass through - return $this->format_address($companyArr,$args); + /** + * Returns a formatted fullname (optionally including ID + first line of addr) + * Replaces zeroBS_companyName + * + * @param int id Company ID + * @param array Company array (if already loaded can pass) + * @param array args (see format_fullname func) + * + * @return string Company full name + */ + public function getCompanyNameEtc( $id = -1, $companyArr = false, $args = array() ) { - } + global $zbs; - return false; - - } - + $id = (int) $id; - /** - * Returns a formatted address of a Company (2nd addr) - * Replaces zeroBS_companySecondAddr - * - * @param int id Company ID - * @param array Company array (if already loaded can pass) - * @param array args (see format_address func) - * - * @return string Company addr html - */ - public function getCompany2ndAddress($id=-1,$companyArr=false,$args=array()){ + // this makes sure it uses name not 'fname' + $args['company'] = true; - global $zbs; + if ( $id > 0 ) { - $id = (int)$id; + // get a limited-fields contact obj + $company = $zbs->DAL->companies->getCompany( + $id, + array( + 'withCustomFields' => false, + 'fields' => array( 'zbsco_addr1', 'zbsco_name' ), + 'ignoreowner' => true, + ) + ); + if ( isset( $company ) && is_array( $company ) && isset( $company['name'] ) ) { + return $this->format_name_etc( $company, $args ); + } + } elseif ( is_array( $companyArr ) ) { - $args['secondaddr'] = true; + // pass through + return $this->format_name_etc( $companyArr, $args ); - if ($id > 0){ + } - // get a limited-fields company obj - // this is hacky, but basically get whole basic company record for this for now, because - // this doesn't properly get addr custom fields: - // $company = $this->getContact($id,array('withCustomFields' => false,'fields'=>$this->field_list_address2,'ignoreowner'=>true)); - $company = $this->getCompany($id,array('withCustomFields' => true,'ignoreowner'=>true)); - if (isset($company) && is_array($company) && isset($company['addr1'])) - return $this->format_address($company,$args); + return false; + } - } elseif (is_array($companyArr)){ + /** + * Returns a formatted address of a contact + * Replaces zeroBS_companyAddr + * + * @param int id Company ID + * @param array Company array (if already loaded can pass) + * @param array args (see format_address func) + * + * @return string Company addr html + */ + public function getCompanyAddress( $id = -1, $companyArr = false, $args = array() ) { - // pass through - return $this->format_address($companyArr,$args); + global $zbs; - } + $id = (int) $id; - return false; - - } - - /** - * Returns a Company's tag array - * - * @param int id Company ID - * - * @return mixed - */ - public function getCompanyTags($id=-1){ + if ( $id > 0 ) { - global $zbs; + // get a limited-fields company obj + // this is hacky, but basically get whole basic company record for this for now, because + // this doesn't properly get addr custom fields: + // $company = $this->getContact($id,array('withCustomFields' => false,'fields'=>$this->field_list_address2,'ignoreowner'=>true)); + $company = $this->getCompany( + $id, + array( + 'withCustomFields' => true, + 'ignoreowner' => true, + ) + ); + if ( isset( $company ) && is_array( $company ) && isset( $company['addr1'] ) ) { + return $this->format_address( $company, $args ); + } + } elseif ( is_array( $companyArr ) ) { - $id = (int)$id; + // pass through + return $this->format_address( $companyArr, $args ); - if ($id > 0){ + } - return $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_COMPANY,'objid'=>$id)); + return false; + } - } + /** + * Returns a formatted address of a Company (2nd addr) + * Replaces zeroBS_companySecondAddr + * + * @param int id Company ID + * @param array Company array (if already loaded can pass) + * @param array args (see format_address func) + * + * @return string Company addr html + */ + public function getCompany2ndAddress( $id = -1, $companyArr = false, $args = array() ) { - return false; - - } + global $zbs; + $id = (int) $id; - /** - * Returns last contacted uts against a Company - * - * @param int id Company ID - * - * @return int Contact last contacted date as uts (or -1) - */ - public function getCompanyLastContactUTS($id=-1){ + $args['secondaddr'] = true; - global $zbs; + if ( $id > 0 ) { - $id = (int)$id; + // get a limited-fields company obj + // this is hacky, but basically get whole basic company record for this for now, because + // this doesn't properly get addr custom fields: + // $company = $this->getContact($id,array('withCustomFields' => false,'fields'=>$this->field_list_address2,'ignoreowner'=>true)); + $company = $this->getCompany( + $id, + array( + 'withCustomFields' => true, + 'ignoreowner' => true, + ) + ); + if ( isset( $company ) && is_array( $company ) && isset( $company['addr1'] ) ) { + return $this->format_address( $company, $args ); + } + } elseif ( is_array( $companyArr ) ) { - if ($id > 0){ + // pass through + return $this->format_address( $companyArr, $args ); - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_COMPANY, - 'colname' => 'zbsco_lastcontacted', - 'ignoreowner' => true)); + } - } + return false; + } - return false; - - } + /** + * Returns a Company's tag array + * + * @param int id Company ID + * + * @return mixed + */ + public function getCompanyTags( $id = -1 ) { - /** - * updates lastcontacted date for a Company - * - * @param int id Company ID - * @param int uts last contacted - * - * @return bool - */ - public function setCompanyLastContactUTS($id=-1,$lastContactedUTS=-1){ + global $zbs; - global $zbs; + $id = (int) $id; - $id = (int)$id; + if ( $id > 0 ) { - if ($id > 0){ + return $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_COMPANY, + 'objid' => $id, + ) + ); - return $this->addUpdateCompany(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbsco_lastcontacted','val' => $lastContactedUTS,'type' => '%d') - ))); + } - } + return false; + } - return false; - - } + /** + * Returns last contacted uts against a Company + * + * @param int id Company ID + * + * @return int Contact last contacted date as uts (or -1) + */ + public function getCompanyLastContactUTS( $id = -1 ) { - /** - * Returns a set of social accounts for a Company (tw,li,fb) - * - * @param int id Company ID - * - * @return array social acc's - */ - // this is not used yet, ahead of time :) - will work tho ;) - public function getCompanySocials($id=-1){ + global $zbs; - global $zbs; + $id = (int) $id; - $id = (int)$id; + if ( $id > 0 ) { - if ($id > 0){ + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_COMPANY, + 'colname' => 'zbsco_lastcontacted', + 'ignoreowner' => true, + ) + ); - // lazy 3 queries, optimise later + } - $tw = $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_COMPANY, - 'colname' => 'zbsco_tw', - 'ignoreowner' => true)); + return false; + } - $li = $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_COMPANY, - 'colname' => 'zbsco_li', - 'ignoreowner' => true)); + /** + * updates lastcontacted date for a Company + * + * @param int id Company ID + * @param int uts last contacted + * + * @return bool + */ + public function setCompanyLastContactUTS( $id = -1, $lastContactedUTS = -1 ) { - $fb = $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_COMPANY, - 'colname' => 'zbsco_fb', - 'ignoreowner' => true)); + global $zbs; - return array('tw'=>$tw,'li' => $li, 'fb' => $fb); + $id = (int) $id; + + if ( $id > 0 ) { + + return $this->addUpdateCompany( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsco_lastcontacted', + 'val' => $lastContactedUTS, + 'type' => '%d', + ), + ), + ) + ); - } + } - return false; - - } - - /** - * Returns the next company ID and the previous company ID - * Used for the navigation between companies. - * - * @param int id - * - * @return array int id - */ - public function getCompanyPrevNext($id=-1){ + return false; + } - global $ZBSCRM_t, $wpdb; + /** + * Returns a set of social accounts for a Company (tw,li,fb) + * + * @param int id Company ID + * + * @return array social acc's + */ + // this is not used yet, ahead of time :) - will work tho ;) + public function getCompanySocials( $id = -1 ) { - if($id > 0){ - //then run the queries.. - $nextSQL = $this->prepare("SELECT MIN(ID) FROM ".$ZBSCRM_t['companies']." WHERE ID > %d", $id); + global $zbs; - $res['next'] = $wpdb->get_var($nextSQL); + $id = (int) $id; - $prevSQL = $this->prepare("SELECT MAX(ID) FROM ".$ZBSCRM_t['companies']." WHERE ID < %d", $id); + if ( $id > 0 ) { - $res['prev'] = $wpdb->get_var($prevSQL); + // lazy 3 queries, optimise later - return $res; + $tw = $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_COMPANY, + 'colname' => 'zbsco_tw', + 'ignoreowner' => true, + ) + ); - } + $li = $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_COMPANY, + 'colname' => 'zbsco_li', + 'ignoreowner' => true, + ) + ); - return false; + $fb = $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_COMPANY, + 'colname' => 'zbsco_fb', + 'ignoreowner' => true, + ) + ); - } + return array( + 'tw' => $tw, + 'li' => $li, + 'fb' => $fb, + ); + } - /** - * Takes full object and makes a "list view" boiled down version - * Used to generate listview objs - * - * @param array $obj (clean obj) - * - * @return array (listview ready obj) - */ - public function listViewObj($company=false,$columnsRequired=array()){ + return false; + } - if (is_array($company) && isset($company['id'])){ + /** + * Returns the next company ID and the previous company ID + * Used for the navigation between companies. + * + * @param int id + * + * @return array int id + */ + public function getCompanyPrevNext( $id = -1 ) { - // copy whole obj - $resArr = $company; + global $ZBSCRM_t, $wpdb; - // here I've translated from DAL2 version (from AJAX) so commented out is no longer req. - // ... or they'll naturally be in DAL3 model already + if ( $id > 0 ) { + // then run the queries.. + $nextSQL = $this->prepare( 'SELECT MIN(ID) FROM ' . $ZBSCRM_t['companies'] . ' WHERE ID > %d', $id ); - //$resArr['id'] = $company['id']; - //$resArr['name'] = $company['coname']; - $resArr['avatar'] = false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $res['next'] = $wpdb->get_var( $nextSQL ); - #} Format the date in the list view.. - //$formatted_date = zeroBSCRM_date_i18n(-1, strtotime($obj['created'])); - // let it use proper obj. - //$resArr['added'] = $company['created_date']; + $prevSQL = $this->prepare( 'SELECT MAX(ID) FROM ' . $ZBSCRM_t['companies'] . ' WHERE ID < %d', $id ); - #} Custom columns + $res['prev'] = $wpdb->get_var( $prevSQL ); - #} Tags - if (in_array('tagged', $columnsRequired)){ + return $res; - $resArr['tags'] = $company['tags']; + } - } - - // Total value - if (in_array('totalvalue', $columnsRequired)){ + return false; + } - #} Calc total value + add to return array - $resArr['totalvalue'] = zeroBSCRM_formatCurrency(0); if (isset($company['total_value'])) $resArr['totalvalue'] = zeroBSCRM_formatCurrency($company['total_value']); + /** + * Takes full object and makes a "list view" boiled down version + * Used to generate listview objs + * + * @param array $obj (clean obj) + * + * @return array (listview ready obj) + */ + public function listViewObj( $company = false, $columnsRequired = array() ) { - } + if ( is_array( $company ) && isset( $company['id'] ) ) { + // copy whole obj + $resArr = $company; - // When Company<->Quotes: - // Quotes - /*if ( in_array( 'quotetotal', $columnsRequired ) ) { - if ( isset( $company['quotes_total'] ) ) { - $resArr['quotestotal'] = zeroBSCRM_formatCurrency( $company['quotes_total'] ); - } - else { - $resArr['quotestotal'] = zeroBSCRM_formatCurrency( 0 ); - } - }*/ + // here I've translated from DAL2 version (from AJAX) so commented out is no longer req. + // ... or they'll naturally be in DAL3 model already - // Invoices - if ( in_array('invoicetotal', $columnsRequired ) ) { - if ( isset( $company['invoices_total'] ) ) { + // $resArr['id'] = $company['id']; + // $resArr['name'] = $company['coname']; + $resArr['avatar'] = false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $resArr['invoicestotal'] = zeroBSCRM_formatCurrency( $company['invoices_total'] ); + #} Format the date in the list view.. + // $formatted_date = zeroBSCRM_date_i18n(-1, strtotime($obj['created'])); + // let it use proper obj. + // $resArr['added'] = $company['created_date']; - // also pass total without formatting (used for hasinvoices check) - $resArr['invoices_total_value'] = $company['invoices_total']; - } - else { - $resArr['invoicestotal'] = zeroBSCRM_formatCurrency( 0 ); - } - } + #} Custom columns - // Transactions - if (in_array('transactiontotal', $columnsRequired)){ + #} Tags + if ( in_array( 'tagged', $columnsRequired ) ) { - $resArr['transactionstotal'] = zeroBSCRM_formatCurrency(0); if (isset($company['transactions_value'])) $resArr['transactionstotal'] = zeroBSCRM_formatCurrency($company['transactions_value']); + $resArr['tags'] = $company['tags']; - } - // v3.0 - if (isset($company['transactions_total'])){ + } - // DAL2 way, brutal effort. - $resArr['transactions_total'] = zeroBSCRM_formatCurrency($company['transactions_total']); + // Total value + if ( in_array( 'totalvalue', $columnsRequired ) ) { - // also pass total without formatting (used for hastransactions check) - $resArr['transactions_total_value'] = $company['transactions_total']; + #} Calc total value + add to return array + $resArr['totalvalue'] = zeroBSCRM_formatCurrency( 0 ); + if ( isset( $company['total_value'] ) ) { + $resArr['totalvalue'] = zeroBSCRM_formatCurrency( $company['total_value'] ); + } + } - } + // When Company<->Quotes: + // Quotes + /* + if ( in_array( 'quotetotal', $columnsRequired ) ) { + if ( isset( $company['quotes_total'] ) ) { + $resArr['quotestotal'] = zeroBSCRM_formatCurrency( $company['quotes_total'] ); + } + else { + $resArr['quotestotal'] = zeroBSCRM_formatCurrency( 0 ); + } + }*/ + + // Invoices + if ( in_array( 'invoicetotal', $columnsRequired ) ) { + if ( isset( $company['invoices_total'] ) ) { + + $resArr['invoicestotal'] = zeroBSCRM_formatCurrency( $company['invoices_total'] ); + + // also pass total without formatting (used for hasinvoices check) + $resArr['invoices_total_value'] = $company['invoices_total']; + } else { + $resArr['invoicestotal'] = zeroBSCRM_formatCurrency( 0 ); + } + } - // avatar mode - $avatarMode = zeroBSCRM_getSetting( 'avatarmode' ); + // Transactions + if ( in_array( 'transactiontotal', $columnsRequired ) ) { - #} Contacts at company - $contactsAtCo = zeroBS_getCustomers(true,1000,0,false,false,'',false,false,$company['id']); - - // build as str - $resArr['contacts'] = ''; + $resArr['transactionstotal'] = zeroBSCRM_formatCurrency( 0 ); + if ( isset( $company['transactions_value'] ) ) { + $resArr['transactionstotal'] = zeroBSCRM_formatCurrency( $company['transactions_value'] ); + } + } + // v3.0 + if ( isset( $company['transactions_total'] ) ) { - // when a company had many contacts the UI was breached, here we max out at 4... - $contactCount = 0; + // DAL2 way, brutal effort. + $resArr['transactions_total'] = zeroBSCRM_formatCurrency( $company['transactions_total'] ); - foreach ( $contactsAtCo as $contact ){ + // also pass total without formatting (used for hastransactions check) + $resArr['transactions_total_value'] = $company['transactions_total']; - // stop at 4 - if ($contactCount >= 4){ + } - $resArr['contacts'] .= '...'; - break; - } + // avatar mode + $avatarMode = zeroBSCRM_getSetting( 'avatarmode' ); - // add avatar/label - if ( $avatarMode !== 3 ) { - $resArr['contacts'] .= zeroBS_getCustomerIcoLinked($contact['id']); // or zeroBS_getCustomerIcoLinkedLabel? - } - else { - // no avatars, use labels - $resArr['contacts'] .= zeroBS_getCustomerLinkedLabel($contact['id']); - } + #} Contacts at company + $contactsAtCo = zeroBS_getCustomers( true, 1000, 0, false, false, '', false, false, $company['id'] ); - $contactCount++; - - } + // build as str + $resArr['contacts'] = ''; - return $resArr; + // when a company had many contacts the UI was breached, here we max out at 4... + $contactCount = 0; + foreach ( $contactsAtCo as $contact ) { - } + // stop at 4 + if ( $contactCount >= 4 ) { - return false; + $resArr['contacts'] .= '...'; + break; + } - } + // add avatar/label + if ( $avatarMode !== 3 ) { + $resArr['contacts'] .= zeroBS_getCustomerIcoLinked( $contact['id'] ); // or zeroBS_getCustomerIcoLinkedLabel? + } else { + // no avatars, use labels + $resArr['contacts'] .= zeroBS_getCustomerLinkedLabel( $contact['id'] ); + } + ++$contactCount; - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * This does so based on the objectModel! - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - private function db_ready_company($obj=false){ + } - // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); + return $resArr; - } + } + return false; + } - // =============================================================================== - // ============ Formatting =================================================== + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * This does so based on the objectModel! + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + private function db_ready_company( $obj = false ) { - /** - * Returns a formatted company name +- id, address (e.g. Automattic Ltd. 12 London Street #23) - * - * @param array $obj (tidied db obj) - * - * @return string name - */ - public function format_name_etc( $companyArr=array(), $args=array() ){ + // use the generic? (override here if necessary) + return $this->db_ready_obj( $obj ); + } - #} =========== LOAD ARGS ============== - $defaultArgs = array( + // =============================================================================== + // ============ Formatting =================================================== - 'incFirstLineAddr' => false, - 'incID' => false + /** + * Returns a formatted company name +- id, address (e.g. Automattic Ltd. 12 London Street #23) + * + * @param array $obj (tidied db obj) + * + * @return string name + */ + public function format_name_etc( $companyArr = array(), $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + 'incFirstLineAddr' => false, + 'incID' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + $str = ''; + if ( isset( $companyArr['name'] ) ) { + $str = $companyArr['name']; + } - $str = ''; if (isset($companyArr['name'])) $str = $companyArr['name']; - - // First line of addr? - if ($incFirstLineAddr) if (isset($companyArr['addr1']) && !empty($companyArr['addr1'])) $str .= ' ('.$companyArr['addr1'].')'; + // First line of addr? + if ( $incFirstLineAddr ) { + if ( isset( $companyArr['addr1'] ) && ! empty( $companyArr['addr1'] ) ) { + $str .= ' (' . $companyArr['addr1'] . ')'; + } + } - // ID? - if ($incID) $str .= ' #'.$companyArr['id']; + // ID? + if ( $incID ) { + $str .= ' #' . $companyArr['id']; + } - return $str; - } + return $str; + } - // =========== / Formatting =================================================== - // =============================================================================== + // =========== / Formatting =================================================== + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.EventReminders.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.EventReminders.php index 3d497d43709f..f2c5dda8da3f 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.EventReminders.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.EventReminders.php @@ -1,5 +1,6 @@ -> Event Reminders (for events/tasks) -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Event Reminders (for events/tasks) + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_eventreminders extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_TASK_REMINDER; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase, Squiz.Commenting.VariableComment.Missing - protected $objectDBPrefix = 'zbser_'; - protected $objectModel = array( - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'event' => array('fieldname' => 'zbser_event', 'format' => 'int'), - 'remind_at' => array('fieldname' => 'zbser_remind_at', 'format' => 'int'), - 'sent' => array('fieldname' => 'zbser_sent', 'format' => 'int'), - 'created' => array('fieldname' => 'zbser_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbser_lastupdated', 'format' => 'uts') - - ); - - - function __construct($args=array()) { - - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - - } - - // ==================================================================================== - // =========== EVENTREMINDER ======================================================= - - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ - - return $this->getEventreminder($ID); - - } - - // generic get (by ID list) - // Super simplistic wrapper used by MVP Export v3.0 - public function getIDList($IDs=false){ - - return $this->getEventReminders(array( - 'inArr' => $IDs, - 'page' => -1, - 'perPage' => -1 - )); - - } - - /** - * returns full eventreminder line +- details - * - * @param int id contact id - * @param array $args Associative array of arguments - * - * @return array eventreminder object - */ - public function getEventreminder($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK_REMINDER ), // this'll let you not-check the owner of obj - - // returns scalar ID of line - 'onlyID' => false, - - 'fields' => false // false = *, array = fieldnames - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check ID - $id = (int)$id; - if ( - (!empty($id) && $id > 0) - || - (!empty($email)) - || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ - - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; - - - #} ============= PRE-QUERY ============ - - $selector = 'eventreminder.*'; + protected $objectType = ZBS_TYPE_TASK_REMINDER; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase, Squiz.Commenting.VariableComment.Missing + protected $objectDBPrefix = 'zbser_'; + protected $objectModel = array( + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'event' => array( + 'fieldname' => 'zbser_event', + 'format' => 'int', + ), + 'remind_at' => array( + 'fieldname' => 'zbser_remind_at', + 'format' => 'int', + ), + 'sent' => array( + 'fieldname' => 'zbser_sent', + 'format' => 'int', + ), + 'created' => array( + 'fieldname' => 'zbser_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbser_lastupdated', + 'format' => 'uts', + ), + + ); + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + } + + // ==================================================================================== + // =========== EVENTREMINDER ======================================================= + + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { + + return $this->getEventreminder( $ID ); + } + + // generic get (by ID list) + // Super simplistic wrapper used by MVP Export v3.0 + public function getIDList( $IDs = false ) { + + return $this->getEventReminders( + array( + 'inArr' => $IDs, + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + /** + * returns full eventreminder line +- details + * + * @param int id contact id + * @param array $args Associative array of arguments + * + * @return array eventreminder object + */ + public function getEventreminder( $id = -1, $args = array() ) { + + global $zbs; + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK_REMINDER ), // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + 'fields' => false, // false = *, array = fieldnames + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + #} Check ID + $id = (int) $id; + if ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $email ) ) + || + ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) + ) { + + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $extraSelect = ''; + + #} ============= PRE-QUERY ============ + + $selector = 'eventreminder.*'; if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $selector = ''; - - // always needs id, so add if not present - if (!in_array('ID',$fields)) $selector = 'eventreminder.ID'; + $selector = ''; - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'eventreminder.'.$f; - } - } else if ($onlyID){ - $selector = 'eventreminder.ID'; - } + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'eventreminder.ID'; + } - #} ============ / PRE-QUERY =========== + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'eventreminder.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'eventreminder.ID'; + } + #} ============ / PRE-QUERY =========== - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['eventreminders'].' as eventreminder'; - #} ============= WHERE ================ + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['eventreminders'] . ' as eventreminder'; + #} ============= WHERE ================ - if (!empty($id) && $id > 0){ + if ( ! empty( $id ) && $id > 0 ) { - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - } + } - #} ============ / WHERE ============== + #} ============ / WHERE ============== - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership + + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); + + try { + + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); + + } catch ( Exception $e ) { + + #} General SQL Err + $this->catchSQLError( $e ); + + } + + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { + + #} Has results, tidy + return + + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } + + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_eventreminder( $potentialRes ); + } + + return $res; + + } + } // / if ID + + return false; + } + + /** + * returns eventreminder detail lines + * + * @param array $args Associative array of arguments + * + * @return array of eventreminder lines + */ + public function getEventreminders( $args = array() ) { + + global $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'eventID' => false, + + // due date + 'dueBefore' => false, // uts (due before) + 'dueAfter' => false, // uts (due after) + + // status + 'sent' => 0, // (if set bool) (false = hasn't been sent, true = has been sent) + + // returns + 'count' => false, + 'withDueUTS' => false, // if true returns 'due' field (UTS due) - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 100, + 'whereCase' => 'AND', // DEFAULT = AND - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); - - try { - - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $this->catchSQLError($e); - - } - - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { - - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID) return $potentialRes->ID; - - // tidy - if (is_array($fields)){ - // guesses fields based on table col names - $res = $this->lazyTidyGeneric($potentialRes); - } else { - // proper tidy - $res = $this->tidy_eventreminder($potentialRes); - } - - return $res; - - } - - } // / if ID - - return false; - - } - - /** - * returns eventreminder detail lines - * - * @param array $args Associative array of arguments - * - * @return array of eventreminder lines - */ - public function getEventreminders($args=array()){ - - global $zbs; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // Search/Filtering (leave as false to ignore) - 'eventID' => false, - - // due date - 'dueBefore' => false, // uts (due before) - 'dueAfter' => false, // uts (due after) - - // status - 'sent' => 0, // (if set bool) (false = hasn't been sent, true = has been sent) - - // returns - 'count' => false, - 'withDueUTS' => false, // if true returns 'due' field (UTS due) - - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 100, - 'whereCase' => 'AND', // DEFAULT = AND - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK_REMINDER ), // this'll let you not-check the owner of obj - - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK_REMINDER ), // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - global $ZBSCRM_t,$wpdb,$zbs; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; + global $ZBSCRM_t, $wpdb, $zbs; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; - #} ============= PRE-QUERY ============ + #} ============= PRE-QUERY ============ - #} Capitalise this - $sortOrder = strtoupper($sortOrder); + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); - // If just count, turn off any extra gumpf - if ($count) { + // If just count, turn off any extra gumpf + if ( $count ) { - $withDueUTS = false; + $withDueUTS = false; - } + } - // include 'due' column + // include 'due' column // @phan-suppress-next-line PhanImpossibleCondition -- This is false by default but can be overridden by $args. - if ($withDueUTS){ - - $extraSelect .= ',(eventreminder.zbser_remind_at + (SELECT zbse_start FROM '.$ZBSCRM_t['events'].' WHERE ID = eventreminder.zbser_event)) due'; + if ( $withDueUTS ) { - } + $extraSelect .= ',(eventreminder.zbser_remind_at + (SELECT zbse_start FROM ' . $ZBSCRM_t['events'] . ' WHERE ID = eventreminder.zbser_event)) due'; - #} ============ / PRE-QUERY =========== - - #} Build query - $query = "SELECT eventreminder.*".$extraSelect." FROM ".$ZBSCRM_t['eventreminders'].' as eventreminder'.$joinQ; + } - #} Count override - if ($count) $query = "SELECT COUNT(eventreminder.ID) FROM ".$ZBSCRM_t['eventreminders'].' as eventreminder'.$joinQ; + #} ============ / PRE-QUERY =========== - #} ============= WHERE ================ + #} Build query + $query = 'SELECT eventreminder.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['eventreminders'] . ' as eventreminder' . $joinQ; + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(eventreminder.ID) FROM ' . $ZBSCRM_t['eventreminders'] . ' as eventreminder' . $joinQ; + } - #} associated event id - if (!empty($eventID) && $eventID > 0){ + #} ============= WHERE ================ - // has id + type to match to (e.g. quote 123) - // simpler than this, we're not using objid links: $wheres['associatedObjType'] = array('ID','IN','(SELECT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_LINEITEM." AND zbsol_objtype_to = ".ZBS_TYPE_TASK." AND zbsol_objid_to = %d)",$eventID); - $wheres['zbser_event'] = array('zbser_event','=','%d',$eventID); + #} associated event id + if ( ! empty( $eventID ) && $eventID > 0 ) { + // has id + type to match to (e.g. quote 123) + // simpler than this, we're not using objid links: $wheres['associatedObjType'] = array('ID','IN','(SELECT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_LINEITEM." AND zbsol_objtype_to = ".ZBS_TYPE_TASK." AND zbsol_objid_to = %d)",$eventID); + $wheres['zbser_event'] = array( 'zbser_event', '=', '%d', $eventID ); - } + } // dueBefore if ( ! empty( $dueBefore ) && $dueBefore > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - // is (event reminder at (e.g. -86400) + event start time (uts)) before $dueBefore - $wheres['direct'][] = array('(eventreminder.zbser_remind_at + (SELECT zbse_start FROM '.$ZBSCRM_t['events'].' WHERE ID = eventreminder.zbser_event) < %d)',array($dueBefore)); + // is (event reminder at (e.g. -86400) + event start time (uts)) before $dueBefore + $wheres['direct'][] = array( '(eventreminder.zbser_remind_at + (SELECT zbse_start FROM ' . $ZBSCRM_t['events'] . ' WHERE ID = eventreminder.zbser_event) < %d)', array( $dueBefore ) ); } // dueAfter if ( ! empty( $dueAfter ) && $dueAfter > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - // is (event reminder at (e.g. -86400) + event start time (uts)) after $dueAfter - $wheres['direct'][] = array('(eventreminder.zbser_remind_at + (SELECT zbse_start FROM '.$ZBSCRM_t['events'].' WHERE ID = eventreminder.zbser_event) > %d)',array($dueAfter)); + // is (event reminder at (e.g. -86400) + event start time (uts)) after $dueAfter + $wheres['direct'][] = array( '(eventreminder.zbser_remind_at + (SELECT zbse_start FROM ' . $ZBSCRM_t['events'] . ' WHERE ID = eventreminder.zbser_event) > %d)', array( $dueAfter ) ); } - // sent (if set as bool) - if ($sent === true){ - - // has been sent - $wheres['zbser_sent'] = array('zbser_sent','=','1'); - - } elseif ($sent === false){ - - // has not been sent - $wheres['zbser_sent'] = array('zbser_sent','=','-1'); - - } - - #} ============ / WHERE =============== - - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; - - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + // sent (if set as bool) + if ( $sent === true ) { - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'contact'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + // has been sent + $wheres['zbser_sent'] = array( 'zbser_sent', '=', '1' ); - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); - - try { + } elseif ( $sent === false ) { - #} Prep & run query - $queryObj = $this->prepare($query,$params); + // has not been sent + $wheres['zbser_sent'] = array( 'zbser_sent', '=', '-1' ); - #} Catch count + return if requested - if ($count) return $wpdb->get_var($queryObj); - - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $this->catchSQLError($e); - - } - - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { - - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $resArr = $this->tidy_eventreminder($resDataLine); - - $res[] = $resArr; - - } - } - - return $res; - } - - - /** - * Returns a count of event reminders (owned) - * .. inc by status - * - * @return int count - */ - public function getEventReminderCount($args=array()){ - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // Search/Filtering (leave as false to ignore) - - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} ============ / WHERE =============== - $whereArr = array(); + #} CHECK this + reset to default if faulty + if ( ! in_array( $whereCase, array( 'AND', 'OR' ) ) ) { + $whereCase = 'AND'; + } - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_TASK_REMINDER, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner - )); - } + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params, $whereCase ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'contact' ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); + try { - /** - * adds or updates a eventreminder object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateEventreminder($args=array()){ + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - global $ZBSCRM_t,$wpdb,$zbs; + #} Catch count + return if requested + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - 'id' => -1, - 'owner' => -1, + } catch ( Exception $e ) { - // fields (directly) - 'data' => array( + #} General SQL Err + $this->catchSQLError( $e ); - - 'event' => -1, - 'remind_at' => '', - 'sent' => '', - 'lastupdated' => '', + } - // allow this to be set for MS sync etc. - 'created' => -1, + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - ), + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) - // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + // tidy + $resArr = $this->tidy_eventreminder( $resDataLine ); - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newEventreminder (because is migrating, not creating new :) this was -1 before + $res[] = $resArr; - 'do_not_update_blanks' => false // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + } + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } + return $res; + } + + /** + * Returns a count of event reminders (owned) + * .. inc by status + * + * @return int count + */ + public function getEventReminderCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + + // permissions + 'ignoreowner' => true, // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + $whereArr = array(); + + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_TASK_REMINDER, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + } + + /** + * adds or updates a eventreminder object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateEventreminder( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'owner' => -1, + + // fields (directly) + 'data' => array( + + 'event' => -1, + 'remind_at' => '', + 'sent' => '', + 'lastupdated' => '', + + // allow this to be set for MS sync etc. + 'created' => -1, + + ), + + 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newEventreminder (because is migrating, not creating new :) this was -1 before + + 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } - #} =========== / LOAD ARGS ============ + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ - - $id = (int)$id; - - // here we check that the potential owner CAN even own - if ($owner > 0 && !user_can($owner,'admin_zerobs_usr')) $owner = -1; + #} ========== CHECK FIELDS ============ - // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } + $id = (int) $id; + // here we check that the potential owner CAN even own + if ( $owner > 0 && ! user_can( $owner, 'admin_zerobs_usr' ) ) { + $owner = -1; + } - if (is_array($limitedFields)){ + // if owner = -1, add current + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); } - // LIMITED UPDATE (only a few fields.) - if (!is_array($limitedFields) || count ($limitedFields) <= 0) return false; - // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; + if ( is_array( $limitedFields ) ) { - } else { + // LIMITED UPDATE (only a few fields.) + if ( ! is_array( $limitedFields ) || count( $limitedFields ) <= 0 ) { + return false; + } + // REQ. ID too (can only update) + if ( empty( $id ) || $id <= 0 ) { + return false; + } + } else { - // NORMAL, FULL UPDATE + // NORMAL, FULL UPDATE - } + } // if no eventID, return false $event = -1; if ( ! empty( $data['event'] ) ) { $event = (int) $data['event']; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- the block containing this line guarantees the var exists. } - if ($event <= 0 && !$limitedFields) return false; - - #} If no status, and default is specified in settings, add that in :) - /* - if (is_null($data['status']) || !isset($data['status']) || empty($data['status'])){ - - // Default status for obj? -> this one gets for contacts -> $zbsCustomerMeta['status'] = zeroBSCRM_getSetting('defaultstatus'); - - } */ - - #} ========= / CHECK FIELDS =========== - - - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - - - // either ext source + setting, or set by the func call - if ($do_not_update_blanks){ - - // this setting says 'don't override filled-out data with blanks' - // so here we check through any passed blanks + convert to limitedFields - // only matters if $id is set (there is somt to update not add - if (isset($id) && !empty($id) && $id > 0){ - - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_eventreminder($data); - //unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue - //unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - - $origData = $data; //$data = array(); - $limitedData = array(); // array(array('key'=>'zbser_x','val'=>y,'type'=>'%s')) - - // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) - // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates - foreach ($dbData as $k => $v){ - - $intV = (int)$v; - - // only add if valuenot empty - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ - - // add to update arr - $limitedData[] = array( - 'key' => 'zbser_'.$k, // we have to add zbser_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbser_'.$k) - ); - - // add to remade $data for post-update updates - $data[$k] = $v; - - } - - } - - // copy over - $limitedFields = $limitedData; - - } // / if ID - - } // / if do_not_update_blanks - - #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== - - #} ========= BUILD DATA =========== - - $update = false; $dataArr = array(); $typeArr = array(); - - if (is_array($limitedFields)){ - - // LIMITED FIELDS - $update = true; - - // cycle through - foreach ($limitedFields as $field){ - - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } - - } - - // add update time - if (!isset($dataArr['zbser_lastupdated'])){ $dataArr['zbser_lastupdated'] = time(); $typeArr[] = '%d'; } - - } else { - - // FULL UPDATE/INSERT - - // UPDATE - $dataArr = array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, - - - 'zbser_event' => $data['event'], - 'zbser_remind_at' => $data['remind_at'], - 'zbser_sent' => $data['sent'], - 'zbser_lastupdated' => time(), - - ); - - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner - - - '%d', - '%d', - '%d', - '%d', - - ); - - if (!empty($id) && $id > 0){ + if ( $event <= 0 && ! $limitedFields ) { + return false; + } - // is update - $update = true; + #} If no status, and default is specified in settings, add that in :) + /* + if (is_null($data['status']) || !isset($data['status']) || empty($data['status'])){ - } else { + // Default status for obj? -> this one gets for contacts -> $zbsCustomerMeta['status'] = zeroBSCRM_getSetting('defaultstatus'); - // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $typeArr[] = '%d'; - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbser_created'] = $data['created'];$typeArr[] = '%d'; - } else { - $dataArr['zbser_created'] = time(); $typeArr[] = '%d'; - } + } */ - } + #} ========= / CHECK FIELDS =========== - } + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - #} ========= / BUILD DATA =========== + // either ext source + setting, or set by the func call + if ( $do_not_update_blanks ) { - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== + // this setting says 'don't override filled-out data with blanks' + // so here we check through any passed blanks + convert to limitedFields + // only matters if $id is set (there is somt to update not add + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - // if we're passing limitedFields we skip these, for now - // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_eventreminder( $data ); + // unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue + // unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - // verify uniques - if (!$this->verifyUniqueValues($data,$id)) return false; // / fails unique field verify + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbser_x','val'=>y,'type'=>'%s')) - // verify not_empty - if (!$this->verifyNonEmptyValues($data)) return false; // / fails empty field verify + // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) + // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates + foreach ( $dbData as $k => $v ) { - } + $intV = (int) $v; - // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks($dataArr); - - #} ========= / CHECK force_uniques & not_empty ================ - #} ============================================================ - - - #} Check if ID present - if ($update){ + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['eventreminders'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ + // add to update arr + $limitedData[] = array( + 'key' => 'zbser_' . $k, // we have to add zbser_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbser_' . $k ), + ); + // add to remade $data for post-update updates + $data[ $k ] = $v; - // if passing limitedFields instead of data, we ignore the following - // this doesn't work, because data is in args default as arr - //if (isset($data) && is_array($data)){ - // so... - if (!isset($limitedFields) || !is_array($limitedFields) || $limitedFields == -1){ + } + } + // copy over + $limitedFields = $limitedData; - } // / if $data + } // / if ID - // Successfully updated - Return id - return $id; + } // / if do_not_update_blanks - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); + #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== - // FAILED update - return false; + #} ========= BUILD DATA =========== - } + $update = false; + $dataArr = array(); + $typeArr = array(); - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['eventreminders'], - $dataArr, - $typeArr ) > 0){ + if ( is_array( $limitedFields ) ) { - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - - return $newID; + // LIMITED FIELDS + $update = true; - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); + // cycle through + foreach ( $limitedFields as $field ) { - #} Failed to Insert - return false; + // some weird case where getting empties, so added check + if ( ! empty( $field['key'] ) ) { + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } + } - } + // add update time + if ( ! isset( $dataArr['zbser_lastupdated'] ) ) { + $dataArr['zbser_lastupdated'] = time(); + $typeArr[] = '%d'; } + } else { - } + // FULL UPDATE/INSERT - return false; + // UPDATE + $dataArr = array( - } + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, - /** - * updates sent status for an event reminder - * - * @param int id Event Reminder ID - * @param int Sent Status (-1 = unsent, 1 = sent) - * - * @return bool - */ - public function setSentStatus($id=-1,$status=-1){ + 'zbser_event' => $data['event'], + 'zbser_remind_at' => $data['remind_at'], + 'zbser_sent' => $data['sent'], + 'zbser_lastupdated' => time(), - global $zbs; + ); - $id = (int)$id; + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner - if ($id > 0 && in_array($status, array(-1,1))){ + '%d', + '%d', + '%d', + '%d', - return $this->addUpdateEventreminder(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbser_sent','val' => $status,'type' => '%d') - ))); + ); - } + if ( ! empty( $id ) && $id > 0 ) { - return false; - - } + // is update + $update = true; + } else { - /** - * deletes a eventreminder object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteEventreminder($args=array()){ + // INSERT (get's few extra :D) + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbser_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbser_created'] = time(); + $typeArr[] = '%d'; + } + } + } - global $ZBSCRM_t,$wpdb,$zbs; + #} ========= / BUILD DATA =========== - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== - 'id' => -1, - 'saveOrphans' => true + // if we're passing limitedFields we skip these, for now + // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 + if ( ! is_array( $limitedFields ) ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + // verify uniques + if ( ! $this->verifyUniqueValues( $data, $id ) ) { + return false; // / fails unique field verify + } - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ + // verify not_empty + if ( ! $this->verifyNonEmptyValues( $data ) ) { + return false; // / fails empty field verify + } + } + // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections + $dataArr = $this->wpdbChecks( $dataArr ); - } + #} ========= / CHECK force_uniques & not_empty ================ + #} ============================================================ - return zeroBSCRM_db2_deleteGeneric($id,'eventreminders'); + #} Check if ID present + if ( $update ) { - } + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['eventreminders'], + $dataArr, + array( // where + 'ID' => $id, + ), + $typeArr, + array( // where data types + '%d', + ) + ) !== false ) { - return false; + // if passing limitedFields instead of data, we ignore the following + // this doesn't work, because data is in args default as arr + // if (isset($data) && is_array($data)){ + // so... + if ( ! isset( $limitedFields ) || ! is_array( $limitedFields ) || $limitedFields == -1 ) { - } + } // / if $data + // Successfully updated - Return id + return $id; - /** - * deletes all eventreminder objects assigned to event - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteEventRemindersForEvent($args=array()){ + } else { - global $ZBSCRM_t,$wpdb,$zbs; + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // FAILED update + return false; - 'eventID' => -1 + } + } else { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['eventreminders'], + $dataArr, + $typeArr + ) > 0 ) { - #} Check ID & Delete :) - $eventID = (int)$eventID; - if (!empty($eventID) && $eventID > 0) { - - $reminders = $this->getEventreminders(array('eventID'=>$eventID,'perPage'=>1000,'ignoreowner'=>true)); + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - $delcount = 0; - if (is_array($reminders)) foreach ($reminders as $r){ + return $newID; - $delcount += $this->deleteEventreminder(array('id'=>$r['id'])); + } else { - } + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); - return $delcount; + #} Failed to Insert + return false; - } + } + } - return false; + return false; + } + + /** + * updates sent status for an event reminder + * + * @param int id Event Reminder ID + * @param int Sent Status (-1 = unsent, 1 = sent) + * + * @return bool + */ + public function setSentStatus( $id = -1, $status = -1 ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 && in_array( $status, array( -1, 1 ) ) ) { + + return $this->addUpdateEventreminder( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbser_sent', + 'val' => $status, + 'type' => '%d', + ), + ), + ) + ); - } + } - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array eventreminder (clean obj) - */ - private function tidy_eventreminder($obj=false,$withCustomFields=false){ + return false; + } + + /** + * deletes a eventreminder object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteEventreminder( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'saveOrphans' => true, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - $res = false; + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = $obj->zbs_owner; + // delete orphans? + if ( $saveOrphans === false ) { - - $res['event'] = (int)$obj->zbser_event; - $res['remind_at'] = (int)$obj->zbser_remind_at; - $res['sent'] = (int)$obj->zbser_sent; - $res['created'] = (int)$obj->zbser_created; - $res['created_date'] = (isset($obj->zbser_created) && $obj->zbser_created > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbser_created) : false; - $res['lastupdated'] = (int)$obj->zbser_lastupdated; - $res['lastupdated_date'] = (isset($obj->zbser_lastupdated) && $obj->zbser_lastupdated > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbser_lastupdated) : false; + } - // if set: due - if (isset($obj->due)) $res['due'] = (int)$obj->due; + return zeroBSCRM_db2_deleteGeneric( $id, 'eventreminders' ); - } + } + return false; + } + + /** + * deletes all eventreminder objects assigned to event + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteEventRemindersForEvent( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'eventID' => -1, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - return $res; + #} Check ID & Delete :) + $eventID = (int) $eventID; + if ( ! empty( $eventID ) && $eventID > 0 ) { + $reminders = $this->getEventreminders( + array( + 'eventID' => $eventID, + 'perPage' => 1000, + 'ignoreowner' => true, + ) + ); - } + $delcount = 0; + if ( is_array( $reminders ) ) { + foreach ( $reminders as $r ) { + $delcount += $this->deleteEventreminder( array( 'id' => $r['id'] ) ); + } + } - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * This does so based on the objectModel! - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - private function db_ready_eventreminder($obj=false){ + return $delcount; - // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); + } - } + return false; + } + + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array eventreminder (clean obj) + */ + private function tidy_eventreminder( $obj = false, $withCustomFields = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = $obj->zbs_owner; + + $res['event'] = (int) $obj->zbser_event; + $res['remind_at'] = (int) $obj->zbser_remind_at; + $res['sent'] = (int) $obj->zbser_sent; + $res['created'] = (int) $obj->zbser_created; + $res['created_date'] = ( isset( $obj->zbser_created ) && $obj->zbser_created > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbser_created ) : false; + $res['lastupdated'] = (int) $obj->zbser_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbser_lastupdated ) && $obj->zbser_lastupdated > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbser_lastupdated ) : false; + + // if set: due + if ( isset( $obj->due ) ) { + $res['due'] = (int) $obj->due; + } + } - // =========== / EVENTREMINDER ======================================================= - // =============================================================================== + return $res; + } + + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * This does so based on the objectModel! + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + private function db_ready_eventreminder( $obj = false ) { + + // use the generic? (override here if necessary) + return $this->db_ready_obj( $obj ); + } + + // =========== / EVENTREMINDER ======================================================= + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Events.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Events.php index b18f3d8a2ef6..40445193a4e9 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Events.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Events.php @@ -1,5 +1,6 @@ -> Events (tasks) -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Events (tasks) + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_events extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_TASK; - protected $objectDBPrefix = 'zbse_'; - protected $include_in_templating = true; - protected $objectModel = array( - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'title' => array( - 'fieldname' => 'zbse_title', - 'format' => 'str', - 'max_len' => 255 - ), - 'desc' => array( - 'fieldname' => 'zbse_desc', - 'format' => 'str', - 'dal1key' => 'notes', - // max_len = LONGTEXT, unlikely to breach - ), - 'start' => array( - 'fieldname' => 'zbse_start', - 'format' => 'uts', - 'dal1key' => 'from' - ), - 'end' => array( - 'fieldname' => 'zbse_end', - 'format' => 'uts', - 'dal1key' => 'to' - ), - 'complete' => array('fieldname' => 'zbse_complete', 'format' => 'bool'), - 'show_on_portal' => array('fieldname' => 'zbse_show_on_portal', 'format' => 'bool'), - 'show_on_cal' => array('fieldname' => 'zbse_show_on_cal', 'format' => 'bool'), - 'created' => array('fieldname' => 'zbse_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbse_lastupdated', 'format' => 'uts') - - ); - - - function __construct($args=array()) { - - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + protected $objectType = ZBS_TYPE_TASK; + protected $objectDBPrefix = 'zbse_'; + protected $include_in_templating = true; + protected $objectModel = array( + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'title' => array( + 'fieldname' => 'zbse_title', + 'format' => 'str', + 'max_len' => 255, + ), + 'desc' => array( + 'fieldname' => 'zbse_desc', + 'format' => 'str', + 'dal1key' => 'notes', + // max_len = LONGTEXT, unlikely to breach + ), + 'start' => array( + 'fieldname' => 'zbse_start', + 'format' => 'uts', + 'dal1key' => 'from', + ), + 'end' => array( + 'fieldname' => 'zbse_end', + 'format' => 'uts', + 'dal1key' => 'to', + ), + 'complete' => array( + 'fieldname' => 'zbse_complete', + 'format' => 'bool', + ), + 'show_on_portal' => array( + 'fieldname' => 'zbse_show_on_portal', + 'format' => 'bool', + ), + 'show_on_cal' => array( + 'fieldname' => 'zbse_show_on_cal', + 'format' => 'bool', + ), + 'created' => array( + 'fieldname' => 'zbse_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbse_lastupdated', + 'format' => 'uts', + ), + + ); + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= add_filter( 'jpcrm_listview_filters', array( $this, 'add_listview_filters' ) ); } @@ -108,506 +146,575 @@ public function add_listview_filters( $listview_filters ) { return $listview_filters; } + // =============================================================================== + // =========== EVENT ======================================================= - // =============================================================================== - // =========== EVENT ======================================================= - - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ - - return $this->getEvent($ID); - - } - - // generic get (by ID list) - // Super simplistic wrapper used by MVP Export v3.0 - public function getIDList($IDs=false){ - - return $this->getEvents(array( - 'inArr' => $IDs, - 'page' => -1, - 'perPage' => -1 - )); - - } - - // generic get (EVERYTHING) - // expect heavy load! - public function getAll($IDs=false){ - - return $this->getEvents(array( - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => -1, - 'perPage' => -1, - )); - - } - - // generic get count of (EVERYTHING) - public function getFullCount(){ - - return $this->getEvents(array( - 'count' => true, - 'page' => -1, - 'perPage' => -1, - )); - - } - - /** - * returns full event line +- details - * - * @param int id event id - * @param array $args Associative array of arguments - * - * @return array event object - */ - public function getEvent($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - // if theset wo passed, will search based on these - 'externalSource' => false, - 'externalSourceUID' => false, - - // with what? - 'withReminders' => true, - 'withCustomFields' => true, - 'withTags' => true, - 'withAssigned' => true, // return ['contact'] & ['company'] objs if has link - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK), // this'll let you not-check the owner of obj - - // returns scalar ID of line - 'onlyID' => false, - - 'fields' => false // false = *, array = fieldnames - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check ID - $id = (int)$id; - if ( - (!empty($id) && $id > 0) - || - (!empty($email)) - || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ - - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; - - - #} ============= PRE-QUERY ============ - - #} Custom Fields - if ($withCustomFields && !$onlyID){ - - #} Retrieve any cf - $custFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_TASK)); - - #} Cycle through + build into query - if (is_array($custFields)) foreach ($custFields as $cK => $cF){ - - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = event.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '".$cK."'"; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_TASK; - - } - - } - - $selector = 'event.*'; - if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $selector = ''; - - // always needs id, so add if not present - if (!in_array('ID',$fields)) $selector = 'event.ID'; - - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'event.'.$f; - } - } else if ($onlyID){ - $selector = 'event.ID'; - } - - #} ============ / PRE-QUERY =========== - - - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['events'].' as event'; - #} ============= WHERE ================ - - if (!empty($id) && $id > 0){ - - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); - - } - - if (!empty($externalSource) && !empty($externalSourceUID)){ - - $wheres['extsourcecheck'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_TASK." AND zbss_source = %s AND zbss_uid = %s)",array($externalSource,$externalSourceUID)); - - } - - #} ============ / WHERE ============== - - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE - - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); - - try { - - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $this->catchSQLError($e); - - } - - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { - - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID) return $potentialRes->ID; - - // tidy - if (is_array($fields)){ - // guesses fields based on table col names - $res = $this->lazyTidyGeneric($potentialRes); - } else { - // proper tidy - $res = $this->tidy_event($potentialRes,$withCustomFields); - } + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { + return $this->getEvent( $ID ); + } - if ($withReminders){ + // generic get (by ID list) + // Super simplistic wrapper used by MVP Export v3.0 + public function getIDList( $IDs = false ) { + + return $this->getEvents( + array( + 'inArr' => $IDs, + 'page' => -1, + 'perPage' => -1, + ) + ); + } - // add all event reminder lines - $res['reminders'] = $this->DAL()->eventreminders->getEventreminders(array('eventID'=>$potentialRes->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK))); - - } + // generic get (EVERYTHING) + // expect heavy load! + public function getAll( $IDs = false ) { + + return $this->getEvents( + array( + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => -1, + 'perPage' => -1, + ) + ); + } - if ($withTags){ + // generic get count of (EVERYTHING) + public function getFullCount() { - // add all tags lines - $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_TASK,'objid'=>$potentialRes->ID)); - - } + return $this->getEvents( + array( + 'count' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } - if ($withAssigned){ + /** + * returns full event line +- details + * + * @param int id event id + * @param array $args Associative array of arguments + * + * @return array event object + */ + public function getEvent( $id = -1, $args = array() ) { - /* This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + global $zbs; - // add all assigned contacts/companies - $res['contacts'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // if theset wo passed, will search based on these + 'externalSource' => false, + 'externalSourceUID' => false, + + // with what? + 'withReminders' => true, + 'withCustomFields' => true, + 'withTags' => true, + 'withAssigned' => true, // return ['contact'] & ['company'] objs if has link + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + 'fields' => false, // false = *, array = fieldnames + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + #} Check ID + $id = (int) $id; + if ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $email ) ) + || + ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) + ) { + + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $extraSelect = ''; + + #} ============= PRE-QUERY ============ + + #} Custom Fields + if ( $withCustomFields && ! $onlyID ) { + + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_TASK ) ); + + #} Cycle through + build into query + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { + + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . " WHERE zbscf_objid = event.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '" . $cK . "'"; + + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_TASK; + + } + } + } - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + $selector = 'event.*'; + if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $selector = ''; + + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'event.ID'; + } + + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'event.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'event.ID'; + } - .. but we use 1:1, at least now: */ + #} ============ / PRE-QUERY =========== - // add all assigned contacts/companies - $res['contact'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TASK, - 'hasObjIDLinkedTo'=>$potentialRes->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['events'] . ' as event'; + #} ============= WHERE ================ - $res['company'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TASK, - 'hasObjIDLinkedTo'=>$potentialRes->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + if ( ! empty( $id ) && $id > 0 ) { - - } + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - return $res; + } - } + if ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) { - } // / if ID + $wheres['extsourcecheck'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_TASK . ' AND zbss_source = %s AND zbss_uid = %s)', array( $externalSource, $externalSourceUID ) ); - return false; + } - } + #} ============ / WHERE ============== - /** - * returns event detail lines - * - * @param array $args Associative array of arguments - * - * @return array of event lines - */ - public function getEvents($args=array()){ + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - global $zbs; + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches which fields? - 'inArr' => false, - 'isTagged' => false, // 1x INT OR array(1,2,3) - 'isNotTagged' => false, // 1x INT OR array(1,2,3) - 'ownedBy' => false, - 'externalSource' => false, // e.g. paypal - 'olderThan' => false, // uts (on CREATED) - 'newerThan' => false, // uts (on CREATED) - 'assignedContact' => false, // assigned to contact id (int) - 'assignedCompany' => false, // assigned to company id (int) - 'isComplete' => false, // if true, only returns completed - 'isIncomplete' => false, // if true, only returns tasks which are not completed + try { - // dated - 'datedBefore' => false, // uts (on date start) - 'datedAfter' => false, // uts (on date start) + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - // reminder checks (use either, not both) - 'hasReminder' => 0, // (if set as bool) (has any state of reminder attached) - 'hasUnsentReminder' => 0, // (if set as bool) (has reminder attached which has not been sent) + } catch ( Exception $e ) { - // returns - 'count' => false, - 'withReminders' => true, - 'withCustomFields' => true, - 'withTags' => false, - 'withAssigned' => false, // return ['contact'] & ['company'] objs if has link - 'withOwner' => false, - 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) + #} General SQL Err + $this->catchSQLError( $e ); - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 100, - 'whereCase' => 'AND', // DEFAULT = AND + } - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK), // this'll let you not-check the owner of obj + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { + + #} Has results, tidy + return + + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } + + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_event( $potentialRes, $withCustomFields ); + } + + if ( $withReminders ) { + + // add all event reminder lines + $res['reminders'] = $this->DAL()->eventreminders->getEventreminders( + array( + 'eventID' => $potentialRes->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), + ) + ); + + } + + if ( $withTags ) { + + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_TASK, + 'objid' => $potentialRes->ID, + ) + ); + + } + + if ( $withAssigned ) { + + /* + This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + + // add all assigned contacts/companies + $res['contacts'] = $this->DAL()->contacts->getContacts(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + + $res['companies'] = $this->DAL()->companies->getCompanies(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + + .. but we use 1:1, at least now: */ + + // add all assigned contacts/companies + $res['contact'] = $this->DAL()->contacts->getContacts( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TASK, + 'hasObjIDLinkedTo' => $potentialRes->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); + + $res['company'] = $this->DAL()->companies->getCompanies( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TASK, + 'hasObjIDLinkedTo' => $potentialRes->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); + + } + + return $res; + } + } // / if ID - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + return false; + } - global $ZBSCRM_t,$wpdb,$zbs; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; + /** + * returns event detail lines + * + * @param array $args Associative array of arguments + * + * @return array of event lines + */ + public function getEvents( $args = array() ) { - #} ============= PRE-QUERY ============ + global $zbs; - #} Capitalise this - $sortOrder = strtoupper($sortOrder); + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => '', // searches which fields? + 'inArr' => false, + 'isTagged' => false, // 1x INT OR array(1,2,3) + 'isNotTagged' => false, // 1x INT OR array(1,2,3) + 'ownedBy' => false, + 'externalSource' => false, // e.g. paypal + 'olderThan' => false, // uts (on CREATED) + 'newerThan' => false, // uts (on CREATED) + 'assignedContact' => false, // assigned to contact id (int) + 'assignedCompany' => false, // assigned to company id (int) + 'isComplete' => false, // if true, only returns completed + 'isIncomplete' => false, // if true, only returns tasks which are not completed + + // dated + 'datedBefore' => false, // uts (on date start) + 'datedAfter' => false, // uts (on date start) + + // reminder checks (use either, not both) + 'hasReminder' => 0, // (if set as bool) (has any state of reminder attached) + 'hasUnsentReminder' => 0, // (if set as bool) (has reminder attached which has not been sent) + + // returns + 'count' => false, + 'withReminders' => true, + 'withCustomFields' => true, + 'withTags' => false, + 'withAssigned' => false, // return ['contact'] & ['company'] objs if has link + 'withOwner' => false, + 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 100, + 'whereCase' => 'AND', // DEFAULT = AND + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + global $ZBSCRM_t, $wpdb, $zbs; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; + + #} ============= PRE-QUERY ============ + + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); + + #} If just count, turn off any extra gumpf + if ( $count ) { + $withCustomFields = false; + $withTags = false; + $withAssigned = false; + $withOwner = false; + } - #} If just count, turn off any extra gumpf - if ($count) { - $withCustomFields = false; - $withTags = false; - $withAssigned = false; - $withOwner = false; - } + #} If onlyColumns, validate + if ( $onlyColumns ) { - #} If onlyColumns, validate - if ($onlyColumns){ + #} onlyColumns build out a field arr + if ( is_array( $onlyColumns ) && count( $onlyColumns ) > 0 ) { - #} onlyColumns build out a field arr - if (is_array($onlyColumns) && count($onlyColumns) > 0){ + $onlyColumnsFieldArr = array(); + foreach ( $onlyColumns as $col ) { - $onlyColumnsFieldArr = array(); - foreach ($onlyColumns as $col){ + // find db col key from field key (e.g. fname => zbsc_fname) + $dbCol = ''; + if ( isset( $this->objectModel[ $col ] ) && isset( $this->objectModel[ $col ]['fieldname'] ) ) { + $dbCol = $this->objectModel[ $col ]['fieldname']; + } - // find db col key from field key (e.g. fname => zbsc_fname) - $dbCol = ''; if (isset($this->objectModel[$col]) && isset($this->objectModel[$col]['fieldname'])) $dbCol = $this->objectModel[$col]['fieldname']; + if ( ! empty( $dbCol ) ) { - if (!empty($dbCol)){ + $onlyColumnsFieldArr[ $dbCol ] = $col; - $onlyColumnsFieldArr[$dbCol] = $col; + } + } + } - } + // if legit cols: + if ( isset( $onlyColumnsFieldArr ) && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - } + $onlyColumns = true; - } + // If onlyColumns, turn off extras + $withCustomFields = false; + $withTags = false; + $withAssigned = false; + $withOwner = false; - // if legit cols: - if (isset($onlyColumnsFieldArr) && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + } else { - $onlyColumns = true; - - // If onlyColumns, turn off extras - $withCustomFields = false; - $withTags = false; - $withAssigned = false; - $withOwner = false; + // deny + $onlyColumns = false; - } else { + } + } - // deny - $onlyColumns = false; + #} Custom Fields + // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. + if ( $withCustomFields ) { - } + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_TASK ) ); + #} Cycle through + build into query + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { - } + // custom field (e.g. 'third name') it'll be passed here as 'third-name' + // ... problem is mysql does not like that :) so we have to chage here: + // in this case we prepend cf's with cf_ and we switch - for _ + $cKey = 'cf_' . str_replace( '-', '_', $cK ); - #} Custom Fields - // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. - if ($withCustomFields){ - - #} Retrieve any cf - $custFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_TASK)); + // we also check the $sortByField in case that's the same cf + if ( $cK == $sortByField ) { - #} Cycle through + build into query - if (is_array($custFields)) foreach ($custFields as $cK => $cF){ + // sort by + $sortByField = $cKey; - // custom field (e.g. 'third name') it'll be passed here as 'third-name' - // ... problem is mysql does not like that :) so we have to chage here: - // in this case we prepend cf's with cf_ and we switch - for _ - $cKey = 'cf_'.str_replace('-','_',$cK); + // check if sort needs any CAST (e.g. numeric): + $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); - // we also check the $sortByField in case that's the same cf - if ($cK == $sortByField){ + } - // sort by - $sortByField = $cKey; + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = event.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey; - // check if sort needs any CAST (e.g. numeric): - $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_TASK; - } + } + } + } - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = event.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_TASK; + #} ============ / PRE-QUERY =========== - } + #} Build query + $query = 'SELECT event.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['events'] . ' as event' . $joinQ; - } + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(event.ID) FROM ' . $ZBSCRM_t['events'] . ' as event' . $joinQ; + } - #} ============ / PRE-QUERY =========== + #} onlyColumns override + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - #} Build query - $query = "SELECT event.*".$extraSelect." FROM ".$ZBSCRM_t['events'].' as event'.$joinQ; + $columnStr = ''; + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - #} Count override - if ($count) $query = "SELECT COUNT(event.ID) FROM ".$ZBSCRM_t['events'].' as event'.$joinQ; + if ( ! empty( $columnStr ) ) { + $columnStr .= ','; + } + // this presumes str is db-safe? could do with sanitation? + $columnStr .= $colDBKey; - #} onlyColumns override - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + } - $columnStr = ''; - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + $query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['events'] . ' as event' . $joinQ; - if (!empty($columnStr)) $columnStr .= ','; - // this presumes str is db-safe? could do with sanitation? - $columnStr .= $colDBKey; + } - } + #} ============= WHERE ================ - $query = "SELECT ".$columnStr." FROM ".$ZBSCRM_t['events'].' as event'.$joinQ; + #} Add Search phrase + if ( ! empty( $searchPhrase ) ) { - } - - #} ============= WHERE ================ + // search? - ALL THESE COLS should probs have index of FULLTEXT in db? + $searchWheres = array(); + $searchWheres['search_title'] = array( 'zbse_title', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_desc'] = array( 'zbse_desc', 'LIKE', '%s', '%' . $searchPhrase . '%' ); - #} Add Search phrase - if (!empty($searchPhrase)){ + // 3.0.13 - Added ability to search custom fields (optionally) + $customFieldSearch = zeroBSCRM_getSetting( 'customfieldsearch' ); + if ( $customFieldSearch == 1 ) { - // search? - ALL THESE COLS should probs have index of FULLTEXT in db? - $searchWheres = array(); - $searchWheres['search_title'] = array('zbse_title','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_desc'] = array('zbse_desc','LIKE','%s','%'.$searchPhrase.'%'); + // simplistic add + // NOTE: This IGNORES ownership of custom field lines. + $searchWheres['search_customfields'] = array( 'ID', 'IN', '(SELECT zbscf_objid FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objval LIKE %s AND zbscf_objtype = ' . ZBS_TYPE_TASK . ')', '%' . $searchPhrase . '%' ); - // 3.0.13 - Added ability to search custom fields (optionally) - $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); - if ($customFieldSearch == 1){ - - // simplistic add - // NOTE: This IGNORES ownership of custom field lines. - $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE zbscf_objval LIKE %s AND zbscf_objtype = ".ZBS_TYPE_TASK.")",'%'.$searchPhrase.'%'); + } - } + // This generates a query like 'zbse_fname LIKE %s OR zbse_lname LIKE %s', + // which we then need to include as direct subquery (below) in main query :) + $searchQueryArr = $this->buildWheres( $searchWheres, '', array(), 'OR', false ); - // This generates a query like 'zbse_fname LIKE %s OR zbse_lname LIKE %s', - // which we then need to include as direct subquery (below) in main query :) - $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - - if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ + if ( is_array( $searchQueryArr ) && isset( $searchQueryArr['where'] ) && ! empty( $searchQueryArr['where'] ) ) { - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + // add it + $wheres['direct'][] = array( '(' . $searchQueryArr['where'] . ')', $searchQueryArr['params'] ); - } + } + } - } + #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { - #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) - if (is_array($inArr) && count($inArr) > 0){ + // clean for ints + $inArrChecked = array(); + foreach ( $inArr as $x ) { + $inArrChecked[] = (int) $x; } - // clean for ints - $inArrChecked = array(); foreach ($inArr as $x){ $inArrChecked[] = (int)$x; } + // add where + $wheres['inarray'] = array( 'ID', 'IN', '(' . implode( ',', $inArrChecked ) . ')' ); - // add where - $wheres['inarray'] = array('ID','IN','('.implode(',',$inArrChecked).')'); + } - } + #} Owned by + if ( ! empty( $ownedBy ) && $ownedBy > 0 ) { - #} Owned by - if (!empty($ownedBy) && $ownedBy > 0){ - - // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) - // but this is only here until MIGRATED to db2 globally - //$wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); - // Use obj links now - $wheres['ownedBy'] = array('zbs_owner','=','%s',$ownedBy); + // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) + // but this is only here until MIGRATED to db2 globally + // $wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); + // Use obj links now + $wheres['ownedBy'] = array( 'zbs_owner', '=', '%s', $ownedBy ); - } + } - // External sources - if ( !empty( $externalSource ) ){ + // External sources + if ( ! empty( $externalSource ) ) { - // NO owernship built into this, check when roll out multi-layered ownsership - $wheres['externalsource'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_TASK." AND zbss_source = %s)",$externalSource); + // NO owernship built into this, check when roll out multi-layered ownsership + $wheres['externalsource'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_TASK . ' AND zbss_source = %s)', $externalSource ); - } + } // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed @@ -626,1314 +733,1437 @@ public function getEvents($args=array()){ if ( ! empty( $assignedCompany ) && $assignedCompany > 0 ) $wheres['assignedCompany'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TASK . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_to = %d)', $assignedCompany ); // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed - // completed status - if ( $isComplete ) $wheres['status'] = array('zbse_complete','=','1'); - if ( $isIncomplete ) $wheres['status'] = array('zbse_complete','<>','1'); + // completed status + if ( $isComplete ) { + $wheres['status'] = array( 'zbse_complete', '=', '1' ); + } + if ( $isIncomplete ) { + $wheres['status'] = array( 'zbse_complete', '<>', '1' ); + } - #} Is Tagged (expects 1 tag ID OR array) + #} Is Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isTagged) && count($isTagged) == 1) $isTagged = $isTagged[0]; + // catch 1 item arr + if ( is_array( $isTagged ) && count( $isTagged ) == 1 ) { + $isTagged = $isTagged[0]; + } if ( ! empty( $isTagged ) && ! is_array( $isTagged ) && $isTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = event.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_TASK,$isTagged)); + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = event.ID AND zbstl_tagid = %d) > 0)', array( ZBS_TYPE_TASK, $isTagged ) ); - } else if (is_array($isTagged) && count($isTagged) > 0){ + } elseif ( is_array( $isTagged ) && count( $isTagged ) > 0 ) { - // foreach in array :) - $tagStr = ''; - foreach ($isTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + // foreach in array :) + $tagStr = ''; + foreach ( $isTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = event.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_TASK,$tagStr)); + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = event.ID AND zbstl_tagid IN (%s)) > 0)', array( ZBS_TYPE_TASK, $tagStr ) ); - } - #} Is NOT Tagged (expects 1 tag ID OR array) + } + } + #} Is NOT Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isNotTagged) && count($isNotTagged) == 1) $isNotTagged = $isNotTagged[0]; + // catch 1 item arr + if ( is_array( $isNotTagged ) && count( $isNotTagged ) == 1 ) { + $isNotTagged = $isNotTagged[0]; + } if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = event.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_TASK,$isNotTagged)); - - } else if (is_array($isNotTagged) && count($isNotTagged) > 0){ - - // foreach in array :) - $tagStr = ''; - foreach ($isNotTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ - - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = event.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_TASK,$tagStr)); - - } - - } - - - // reminders - if ($hasReminder === true){ - - // has a reminder - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['eventreminders'].' WHERE zbser_event = event.ID) > 0)',array()); - - - } elseif ($hasReminder === false){ - - // has no reminder - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['eventreminders'].' WHERE zbser_event = event.ID) = 0)',array()); - - - } elseif ($hasUnsentReminder === true){ - - // has an unsent reminder - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['eventreminders'].' WHERE zbser_event = event.ID AND zbser_sent = -1) > 0)',array()); - - } elseif ($hasUnsentReminder === false){ - - // has no unsent reminder - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['eventreminders'].' WHERE zbser_event = event.ID AND zbser_sent = -1) = 0)',array()); - - } - - - - #} ============ / WHERE =============== - - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; - - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE - - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'contact'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); - - try { - - #} Prep & run query - $queryObj = $this->prepare($query,$params); - - #} Catch count + return if requested - if ($count) return $wpdb->get_var($queryObj); - - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $this->catchSQLError($e); - - } - - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { - - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // using onlyColumns filter? - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ - - // only coumns return. - $resArr = array(); - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ - - if (isset($resDataLine->$colDBKey)) $resArr[$colStr] = $resDataLine->$colDBKey; - - } - - - } else { - - // tidy - $resArr = $this->tidy_event($resDataLine,$withCustomFields); - - } - - if ($withReminders){ - - // add all event reminder lines - $resArr['reminders'] = $this->DAL()->eventreminders->getEventreminders(array('eventID'=>$resDataLine->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK))); - - } + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = event.ID AND zbstl_tagid = %d) = 0)', array( ZBS_TYPE_TASK, $isNotTagged ) ); - if ($withTags){ + } elseif ( is_array( $isNotTagged ) && count( $isNotTagged ) > 0 ) { - // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_TASK,'objid'=>$resDataLine->ID)); - - } - if ($withAssigned){ - - /* This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) - - // add all assigned contacts/companies - $res['contacts'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); - - .. but we use 1:1, at least now: */ - - // add all assigned contacts/companies - $resArr['contact'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TASK, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - - $resArr['company'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TASK, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); - - - } - - #} With Assigned? - if ($withOwner){ - - $resArr['owner'] = zeroBS_getOwner( $resDataLine->ID, true, ZBS_TYPE_TASK, $resDataLine->zbs_owner ); - - } - - $res[] = $resArr; - - } - } - - return $res; - } - - - - /** - * Returns a count of events (owned) - * .. inc by status - * - * @return int count - */ - public function getEventCount($args=array()){ - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // Search/Filtering (leave as false to ignore) - - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - $whereArr = array(); - - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_TASK, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - } + // foreach in array :) + $tagStr = ''; + foreach ( $isNotTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - /** - * adds or updates a event object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateEvent($args=array()){ + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = event.ID AND zbstl_tagid IN (%s)) = 0)', array( ZBS_TYPE_TASK, $tagStr ) ); - global $ZBSCRM_t,$wpdb,$zbs; - - #} Retrieve any cf - $customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_TASK)); + } + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // reminders + if ( $hasReminder === true ) { - 'id' => -1, - 'owner' => -1, + // has a reminder + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['eventreminders'] . ' WHERE zbser_event = event.ID) > 0)', array() ); - // fields (directly) - 'data' => array( + } elseif ( $hasReminder === false ) { - - 'title' => '', - 'desc' => '', - 'start' => '', - 'end' => '', - 'complete' => '', - 'show_on_portal' => '', - 'show_on_cal' => true, + // has no reminder + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['eventreminders'] . ' WHERE zbser_event = event.ID) = 0)', array() ); - // obj links: - 'contacts' => false, // array of id's - 'companies' => false, // array of id's + } elseif ( $hasUnsentReminder === true ) { - // reminders: - 'reminders' => false, - // will be an array of eventreminder lines (as per matching eventreminder database model) - // note: if no change desired, pass "false" - // if removal of all/change, pass array + // has an unsent reminder + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['eventreminders'] . ' WHERE zbser_event = event.ID AND zbser_sent = -1) > 0)', array() ); - // Note Custom fields may be passed here, but will not have defaults so check isset() + } elseif ( $hasUnsentReminder === false ) { - // tags - 'tags' => -1, // pass an array of tag ids or tag strings - 'tag_mode' => 'replace', // replace|append|remove + // has no unsent reminder + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['eventreminders'] . ' WHERE zbser_event = event.ID AND zbser_sent = -1) = 0)', array() ); - 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) + } - // allow this to be set for MS sync etc. - 'created' => -1, - 'lastupdated' => '', + #} ============ / WHERE =============== - ), + #} CHECK this + reset to default if faulty + if ( ! in_array( $whereCase, array( 'AND', 'OR' ) ) ) { + $whereCase = 'AND'; + } - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) - // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params, $whereCase ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'contact' ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - // this function as DAL1 func did. - 'extraMeta' => -1, - 'automatorPassthrough' => -1, + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newEvent (because is migrating, not creating new :) this was -1 before + try { - 'do_not_update_blanks' => false // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - - // Needs this to grab custom fields (if passed) too :) - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + #} Catch count + return if requested + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } - // only for data, limited fields below - if (is_array($data)) { + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - if (isset($args['data'][$cK])) $data[$cK] = $args['data'][$cK]; + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - } + } - // this takes limited fields + checks through for custom fields present - // (either as key zbse_source or source, for example) - // then switches them into the $data array, for separate update - // where this'll fall over is if NO normal contact data is sent to update, just custom fields - if (is_array($limitedFields) && is_array($customFields)){ + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - //$customFieldKeys = array_keys($customFields); - $newLimitedFields = array(); + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - // cycle through - foreach ($limitedFields as $field){ + // using onlyColumns filter? + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - // some weird case where getting empties, so added check - if (isset($field['key']) && !empty($field['key'])){ + // only coumns return. + $resArr = array(); + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ( str_starts_with( $field['key'], 'zbse_' ) ) { - $dePrefixed = substr( $field['key'], strlen( 'zbse_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( isset( $resDataLine->$colDBKey ) ) { + $resArr[ $colStr ] = $resDataLine->$colDBKey; } + } + } else { + + // tidy + $resArr = $this->tidy_event( $resDataLine, $withCustomFields ); + + } + + if ( $withReminders ) { + + // add all event reminder lines + $resArr['reminders'] = $this->DAL()->eventreminders->getEventreminders( + array( + 'eventID' => $resDataLine->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), + ) + ); + + } + + if ( $withTags ) { + + // add all tags lines + $resArr['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_TASK, + 'objid' => $resDataLine->ID, + ) + ); + + } + if ( $withAssigned ) { + + /* + This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + + // add all assigned contacts/companies + $res['contacts'] = $this->DAL()->contacts->getContacts(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + + $res['companies'] = $this->DAL()->companies->getCompanies(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + + .. but we use 1:1, at least now: */ + + // add all assigned contacts/companies + $resArr['contact'] = $this->DAL()->contacts->getContacts( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TASK, + 'hasObjIDLinkedTo' => $resDataLine->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); + + $resArr['company'] = $this->DAL()->companies->getCompanies( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TASK, + 'hasObjIDLinkedTo' => $resDataLine->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); + + } + + #} With Assigned? + if ( $withOwner ) { + + $resArr['owner'] = zeroBS_getOwner( $resDataLine->ID, true, ZBS_TYPE_TASK, $resDataLine->zbs_owner ); + + } + + $res[] = $resArr; - if (isset($customFields[$field['key']])){ - - // is custom, move to data - $data[$field['key']] = $field['val']; - - } else if (!empty($dePrefixed) && isset($customFields[$dePrefixed])){ - - // is custom, move to data - $data[$dePrefixed] = $field['val']; - - } else { - - // add it to limitedFields (it's not dealt with post-update) - $newLimitedFields[] = $field; - } - - } - - } - - // move this back in - $limitedFields = $newLimitedFields; - unset($newLimitedFields); - - } - - #} =========== / LOAD ARGS ============ - - #} ========== CHECK FIELDS ============ - - $id = (int)$id; - - // here we check that the potential owner CAN even own - if ($owner > 0 && !user_can($owner,'admin_zerobs_usr')) $owner = -1; - - // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } - - - if (is_array($limitedFields)){ - - // LIMITED UPDATE (only a few fields.) - if (!is_array($limitedFields) || count ($limitedFields) <= 0) return false; - // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; - - } else { - - // NORMAL, FULL UPDATE - - } - - - #} If no status, and default is specified in settings, add that in :) - /* - if (is_null($data['status']) || !isset($data['status']) || empty($data['status'])){ - - // Default status for obj? -> this one gets for contacts -> $zbsCustomerMeta['status'] = zeroBSCRM_getSetting('defaultstatus'); - - } - */ - - #} ========= / CHECK FIELDS =========== - - - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - - // this only functions if externalsource is set (e.g. api/form, etc.) - if (isset($data['externalSources']) && is_array($data['externalSources']) && count($data['externalSources']) > 0) { - if (zeroBSCRM_getSetting('fieldoverride') == "1"){ - - $do_not_update_blanks = true; - - } - - } - - // either ext source + setting, or set by the func call - if ($do_not_update_blanks){ - - // this setting says 'don't override filled-out data with blanks' - // so here we check through any passed blanks + convert to limitedFields - // only matters if $id is set (there is somt to update not add - if (isset($id) && !empty($id) && $id > 0){ - - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_event($data); - - $origData = $data; //$data = array(); - $limitedData = array(); // array(array('key'=>'zbse_x','val'=>y,'type'=>'%s')) - - // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) - // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates - foreach ($dbData as $k => $v){ - - $intV = (int)$v; - - // only add if valuenot empty - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ - - // add to update arr - $limitedData[] = array( - 'key' => 'zbse_'.$k, // we have to add zbse_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbse_'.$k) - ); - - // add to remade $data for post-update updates - $data[$k] = $v; - - } - - } - - // copy over - $limitedFields = $limitedData; - - } // / if ID - - } // / if do_not_update_blanks - - #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== - - - #} ========= BUILD DATA =========== - - $update = false; $dataArr = array(); $typeArr = array(); - - if (is_array($limitedFields)){ - - // LIMITED FIELDS - $update = true; - - // cycle through - foreach ($limitedFields as $field){ - - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } - - } - - // add update time - if (!isset($dataArr['zbse_lastupdated'])){ $dataArr['zbse_lastupdated'] = time(); $typeArr[] = '%d'; } - - } else { + } + } - // contacts - avoid dupes - if (isset($data['contacts']) && is_array($data['contacts'])){ + return $res; + } - $coArr = array(); - foreach ($data['contacts'] as $c){ - $cI = (int)$c; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; - } + /** + * Returns a count of events (owned) + * .. inc by status + * + * @return int count + */ + public function getEventCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + + // permissions + 'ignoreowner' => true, // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + $whereArr = array(); + + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_TASK, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + } - // reset the main - if (count($coArr) > 0) - $data['contacts'] = $coArr; - else - $data['contacts'] = 'unset'; - unset($coArr); + /** + * adds or updates a event object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateEvent( $args = array() ) { - } + global $ZBSCRM_t, $wpdb, $zbs; - // companies - avoid dupes - if (isset($data['companies']) && is_array($data['companies'])){ + #} Retrieve any cf + $customFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_TASK ) ); - $coArr = array(); - foreach ($data['companies'] as $c){ - $cI = (int)$c; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; - } + #} ============ LOAD ARGS ============= + $defaultArgs = array( - // reset the main - if (count($coArr) > 0) - $data['companies'] = $coArr; - else - $data['companies'] = 'unset'; - unset($coArr); + 'id' => -1, + 'owner' => -1, - } + // fields (directly) + 'data' => array( - // FULL UPDATE/INSERT + 'title' => '', + 'desc' => '', + 'start' => '', + 'end' => '', + 'complete' => '', + 'show_on_portal' => '', + 'show_on_cal' => true, - // UPDATE - $dataArr = array( + // obj links: + 'contacts' => false, // array of id's + 'companies' => false, // array of id's - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, + // reminders: + 'reminders' => false, + // will be an array of eventreminder lines (as per matching eventreminder database model) + // note: if no change desired, pass "false" + // if removal of all/change, pass array - - 'zbse_title' => $data['title'], - 'zbse_desc' => $data['desc'], - 'zbse_start' => $data['start'], - 'zbse_end' => $data['end'], - 'zbse_complete' => $data['complete'], - 'zbse_show_on_portal' => $data['show_on_portal'], - 'zbse_show_on_cal' => $data['show_on_cal'], - 'zbse_lastupdated' => time(), + // Note Custom fields may be passed here, but will not have defaults so check isset() - ); + // tags + 'tags' => -1, // pass an array of tag ids or tag strings + 'tag_mode' => 'replace', // replace|append|remove - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner + 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) - - '%s', - '%s', - '%d', - '%d', - '%s', - '%d', - '%d', - '%d', + // allow this to be set for MS sync etc. + 'created' => -1, + 'lastupdated' => '', - ); - - if (!empty($id) && $id > 0){ - - // is update - $update = true; - - // events can be re-assigned - if (isset($owner) && !empty($owner) && $owner !== -1){ - - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - - } - - } else { - - // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $typeArr[] = '%d'; - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbse_created'] = $data['created'];$typeArr[] = '%d'; - } else { - $dataArr['zbse_created'] = time(); $typeArr[] = '%d'; - } + ), - } + 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) - } + // this function as DAL1 func did. + 'extraMeta' => -1, + 'automatorPassthrough' => -1, - #} ========= / BUILD DATA =========== + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newEvent (because is migrating, not creating new :) this was -1 before - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== + 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) - // if we're passing limitedFields we skip these, for now - // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } - // verify uniques - if (!$this->verifyUniqueValues($data,$id)) return false; // / fails unique field verify + // Needs this to grab custom fields (if passed) too :) + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { - // verify not_empty - if (!$this->verifyNonEmptyValues($data)) return false; // / fails empty field verify + // only for data, limited fields below + if ( is_array( $data ) ) { - } - - // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks($dataArr); - - #} ========= / CHECK force_uniques & not_empty ================ - #} ============================================================ - - #} Check if ID present - if ($update){ + if ( isset( $args['data'][ $cK ] ) ) { + $data[ $cK ] = $args['data'][ $cK ]; + } + } + } + } - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['events'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ - - // defaults for IA below - $approvedExternalSource = ''; - $againstIDs = array('contacts'=>array(),'companies'=>array()); + // this takes limited fields + checks through for custom fields present + // (either as key zbse_source or source, for example) + // then switches them into the $data array, for separate update + // where this'll fall over is if NO normal contact data is sent to update, just custom fields + if ( is_array( $limitedFields ) && is_array( $customFields ) ) { - // if passing limitedFields instead of data, we ignore the following - // this doesn't work, because data is in args default as arr - //if (isset($data) && is_array($data)){ - // so... - if (!isset($limitedFields) || !is_array($limitedFields) || $limitedFields == -1){ + // $customFieldKeys = array_keys($customFields); + $newLimitedFields = array(); - // OBJ LINKS - to contacts/companies - $this->addUpdateObjectLinks($id,$data['contacts'],ZBS_TYPE_CONTACT); - $this->addUpdateObjectLinks($id,$data['companies'],ZBS_TYPE_COMPANY); - // IA also gets 'againstid' historically, but we'll pass as 'against id's' - $againstIDs = array('contacts'=>$data['contacts'],'companies'=>$data['companies']); + // cycle through + foreach ( $limitedFields as $field ) { - // Event Reminders ==== + // some weird case where getting empties, so added check + if ( isset( $field['key'] ) && ! empty( $field['key'] ) ) { - // event reminder work? - if (isset($data['reminders']) && is_array($data['reminders'])){ + $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( str_starts_with( $field['key'], 'zbse_' ) ) { + $dePrefixed = substr( $field['key'], strlen( 'zbse_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - // if array passed, update, even if removing - if (count($data['reminders']) > 0){ + if ( isset( $customFields[ $field['key'] ] ) ) { - // passed, for now this is BRUTAL and just clears old ones + readds - // once live, discuss how to refactor to be less brutal. - // for now will be fine if you LOAD reminders, edit, addUpdate, -> don't recreate them then rejam in expecting it to know how to deal with :) - // (in which case reminders sent already might get resent, but that's if not following this note ^) + // is custom, move to data + $data[ $field['key'] ] = $field['val']; - // delete all reminders - $this->DAL()->eventreminders->deleteEventRemindersForEvent(array('eventID'=>$id)); + } elseif ( ! empty( $dePrefixed ) && isset( $customFields[ $dePrefixed ] ) ) { - // addupdate each - foreach ($data['reminders'] as $reminder) { + // is custom, move to data + $data[ $dePrefixed ] = $field['val']; - // no point in this: - // slight rejig of passed so works cleanly with data array style - //$reminderID = false; if (isset($reminder['ID'])) $reminderID = $reminder['ID']; - $reminderID = false; + } else { - // if 'event' isn't set, add this event id - // actually hard set. if (!isset($reminder['event'])) - $reminder['event'] = $id; + // add it to limitedFields (it's not dealt with post-update) + $newLimitedFields[] = $field; + } + } + } - $this->DAL()->eventreminders->addUpdateEventreminder(array('id'=>$reminderID,'data'=>$reminder)); + // move this back in + $limitedFields = $newLimitedFields; + unset( $newLimitedFields ); - } + } - } else { + #} =========== / LOAD ARGS ============ - // delete all reminders - $this->DAL()->eventreminders->deleteEventRemindersForEvent(array('eventID'=>$id)); + #} ========== CHECK FIELDS ============ - } + $id = (int) $id; + // here we check that the potential owner CAN even own + if ( $owner > 0 && ! user_can( $owner, 'admin_zerobs_usr' ) ) { + $owner = -1; + } - } + // if owner = -1, add current + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); } - // / Event Reminders ==== + if ( is_array( $limitedFields ) ) { - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + // LIMITED UPDATE (only a few fields.) + if ( ! is_array( $limitedFields ) || count( $limitedFields ) <= 0 ) { + return false; + } + // REQ. ID too (can only update) + if ( empty( $id ) || $id <= 0 ) { + return false; + } + } else { - $this->addUpdateEventTags( - array( - 'id' => $id, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + // NORMAL, FULL UPDATE - } + } - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( - array( - 'obj_id' => $id, - 'obj_type_id' => ZBS_TYPE_TASK, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), - ) - ); // for IA below + #} If no status, and default is specified in settings, add that in :) + /* + if (is_null($data['status']) || !isset($data['status']) || empty($data['status'])){ - // Custom fields? + // Default status for obj? -> this one gets for contacts -> $zbsCustomerMeta['status'] = zeroBSCRM_getSetting('defaultstatus'); - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + } + */ - // any? - if (isset($data[$cK])){ + #} ========= / CHECK FIELDS =========== - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_TASK, - 'objid' => $id, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - } + // this only functions if externalsource is set (e.g. api/form, etc.) + if ( isset( $data['externalSources'] ) && is_array( $data['externalSources'] ) && count( $data['externalSources'] ) > 0 ) { + if ( zeroBSCRM_getSetting( 'fieldoverride' ) == '1' ) { - } + $do_not_update_blanks = true; - // / Custom Fields + } + } - } // / if $data + // either ext source + setting, or set by the func call + if ( $do_not_update_blanks ) { - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // this setting says 'don't override filled-out data with blanks' + // so here we check through any passed blanks + convert to limitedFields + // only matters if $id is set (there is somt to update not add + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - $confirmedExtraMeta = array(); + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_event( $data ); - foreach ($extraMeta as $k => $v){ + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbse_x','val'=>y,'type'=>'%s')) - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) + // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates + foreach ( $dbData as $k => $v ) { - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_TASK,$id,'extra_'.$cleanKey,$v); + $intV = (int) $v; - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { - } + // add to update arr + $limitedData[] = array( + 'key' => 'zbse_' . $k, // we have to add zbse_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbse_' . $k ), + ); - } + // add to remade $data for post-update updates + $data[ $k ] = $v; + } + } - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ + // copy over + $limitedFields = $limitedData; - // catch dirty flag (update of status) (note, after update_post_meta - as separate) - //if (isset($_POST['zbse_status_dirtyflag']) && $_POST['zbse_status_dirtyflag'] == "1"){ - // actually here, it's set above - /* WH not sure if used for this obj: - if (isset($statusChange) && is_array($statusChange)){ + } // / if ID - // status has changed + } // / if do_not_update_blanks - // IA - zeroBSCRM_FireInternalAutomator('event.status.update',array( - 'id'=>$id, - 'againstid' => $id, - 'userMeta'=> $dataArr, - 'from' => $statusChange['from'], - 'to' => $statusChange['to'] - )); + #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== - } */ + #} ========= BUILD DATA =========== - // IA General event update (2.87+) - zeroBSCRM_FireInternalAutomator('event.update',array( - 'id'=>$id, - 'data'=>$data, - 'extsource'=>$approvedExternalSource, - 'againstids'=>$againstIDs, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); + $update = false; + $dataArr = array(); + $typeArr = array(); - + if ( is_array( $limitedFields ) ) { - } + // LIMITED FIELDS + $update = true; - - // Successfully updated - Return id - return $id; + // cycle through + foreach ( $limitedFields as $field ) { - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); + // some weird case where getting empties, so added check + if ( ! empty( $field['key'] ) ) { + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } + } - // FAILED update - return false; + // add update time + if ( ! isset( $dataArr['zbse_lastupdated'] ) ) { + $dataArr['zbse_lastupdated'] = time(); + $typeArr[] = '%d'; } + } else { + + // contacts - avoid dupes + if ( isset( $data['contacts'] ) && is_array( $data['contacts'] ) ) { + + $coArr = array(); + foreach ( $data['contacts'] as $c ) { + $cI = (int) $c; + if ( $cI > 0 && ! in_array( $cI, $coArr ) ) { + $coArr[] = $cI; + } + } + + // reset the main + if ( count( $coArr ) > 0 ) { + $data['contacts'] = $coArr; + } else { + $data['contacts'] = 'unset'; + } + unset( $coArr ); - } + } - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['events'], - $dataArr, - $typeArr ) > 0){ + // companies - avoid dupes + if ( isset( $data['companies'] ) && is_array( $data['companies'] ) ) { + + $coArr = array(); + foreach ( $data['companies'] as $c ) { + $cI = (int) $c; + if ( $cI > 0 && ! in_array( $cI, $coArr ) ) { + $coArr[] = $cI; + } + } + + // reset the main + if ( count( $coArr ) > 0 ) { + $data['companies'] = $coArr; + } else { + $data['companies'] = 'unset'; + } + unset( $coArr ); - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; + } - // defaults for IA below - $approvedExternalSource = ''; - $againstIDs = array('contacts'=>array(),'companies'=>array()); + // FULL UPDATE/INSERT - // Event Reminders ==== + // UPDATE + $dataArr = array( - // event reminder work? - if (isset($data['reminders']) && is_array($data['reminders'])){ + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, - // if array passed, update, even if removing - if (count($data['reminders']) > 0){ + 'zbse_title' => $data['title'], + 'zbse_desc' => $data['desc'], + 'zbse_start' => $data['start'], + 'zbse_end' => $data['end'], + 'zbse_complete' => $data['complete'], + 'zbse_show_on_portal' => $data['show_on_portal'], + 'zbse_show_on_cal' => $data['show_on_cal'], + 'zbse_lastupdated' => time(), - // passed, for now this is BRUTAL and just clears old ones + readds - // once live, discuss how to refactor to be less brutal. - // for now will be fine if you LOAD reminders, edit, addUpdate, -> don't recreate them then rejam in expecting it to know how to deal with :) - // (in which case reminders sent already might get resent, but that's if not following this note ^) + ); - // delete all reminders - $this->DAL()->eventreminders->deleteEventRemindersForEvent(array('eventID'=>$newID)); + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner - // addupdate each - foreach ($data['reminders'] as $reminder) { + '%s', + '%s', + '%d', + '%d', + '%s', + '%d', + '%d', + '%d', - // no point in this: - // slight rejig of passed so works cleanly with data array style - //$reminderID = false; if (isset($reminder['ID'])) $reminderID = $reminder['ID']; - $reminderID = false; + ); - // if 'event' isn't set, add this event id - // actually hard set.. if (!isset($reminder['event'])) - $reminder['event'] = $newID; + if ( ! empty( $id ) && $id > 0 ) { - $this->DAL()->eventreminders->addUpdateEventreminder(array('id'=>$reminderID,'data'=>$reminder)); + // is update + $update = true; - } + // events can be re-assigned + if ( isset( $owner ) && ! empty( $owner ) && $owner !== -1 ) { - } else { + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; - // delete all reminders - $this->DAL()->eventreminders->deleteEventRemindersForEvent(array('eventID'=>$newID)); + } + } else { + + // INSERT (get's few extra :D) + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbse_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbse_created'] = time(); + $typeArr[] = '%d'; + } + } + } - } + #} ========= / BUILD DATA =========== + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== - } + // if we're passing limitedFields we skip these, for now + // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 + if ( ! is_array( $limitedFields ) ) { - // / Event Reminders ==== + // verify uniques + if ( ! $this->verifyUniqueValues( $data, $id ) ) { + return false; // / fails unique field verify + } - // OBJ LINKS - to contacts/companies - $this->addUpdateObjectLinks($newID,$data['contacts'],ZBS_TYPE_CONTACT); - $this->addUpdateObjectLinks($newID,$data['companies'],ZBS_TYPE_COMPANY); - // IA also gets 'againstid' historically, but we'll pass as 'against id's' - $againstIDs = array('contacts'=>$data['contacts'],'companies'=>$data['companies']); + // verify not_empty + if ( ! $this->verifyNonEmptyValues( $data ) ) { + return false; // / fails empty field verify + } + } - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections + $dataArr = $this->wpdbChecks( $dataArr ); + + #} ========= / CHECK force_uniques & not_empty ================ + #} ============================================================ + + #} Check if ID present + if ( $update ) { + + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['events'], + $dataArr, + array( // where + 'ID' => $id, + ), + $typeArr, + array( // where data types + '%d', + ) + ) !== false ) { + + // defaults for IA below + $approvedExternalSource = ''; + $againstIDs = array( + 'contacts' => array(), + 'companies' => array(), + ); + + // if passing limitedFields instead of data, we ignore the following + // this doesn't work, because data is in args default as arr + // if (isset($data) && is_array($data)){ + // so... + if ( ! isset( $limitedFields ) || ! is_array( $limitedFields ) || $limitedFields == -1 ) { + + // OBJ LINKS - to contacts/companies + $this->addUpdateObjectLinks( $id, $data['contacts'], ZBS_TYPE_CONTACT ); + $this->addUpdateObjectLinks( $id, $data['companies'], ZBS_TYPE_COMPANY ); + // IA also gets 'againstid' historically, but we'll pass as 'against id's' + $againstIDs = array( + 'contacts' => $data['contacts'], + 'companies' => $data['companies'], + ); + + // Event Reminders ==== + + // event reminder work? + if ( isset( $data['reminders'] ) && is_array( $data['reminders'] ) ) { + + // if array passed, update, even if removing + if ( count( $data['reminders'] ) > 0 ) { + + // passed, for now this is BRUTAL and just clears old ones + readds + // once live, discuss how to refactor to be less brutal. + // for now will be fine if you LOAD reminders, edit, addUpdate, -> don't recreate them then rejam in expecting it to know how to deal with :) + // (in which case reminders sent already might get resent, but that's if not following this note ^) + + // delete all reminders + $this->DAL()->eventreminders->deleteEventRemindersForEvent( array( 'eventID' => $id ) ); + + // addupdate each + foreach ( $data['reminders'] as $reminder ) { + + // no point in this: + // slight rejig of passed so works cleanly with data array style + // $reminderID = false; if (isset($reminder['ID'])) $reminderID = $reminder['ID']; + $reminderID = false; + + // if 'event' isn't set, add this event id + // actually hard set. if (!isset($reminder['event'])) + $reminder['event'] = $id; + + $this->DAL()->eventreminders->addUpdateEventreminder( + array( + 'id' => $reminderID, + 'data' => $reminder, + ) + ); + + } + } else { + + // delete all reminders + $this->DAL()->eventreminders->deleteEventRemindersForEvent( array( 'eventID' => $id ) ); + + } + } + + // / Event Reminders ==== + + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { + + $this->addUpdateEventTags( + array( + 'id' => $id, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); + + } + + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $id, + 'obj_type_id' => ZBS_TYPE_TASK, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below + + // Custom fields? + + #} Cycle through + add/update if set + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { + + // any? + if ( isset( $data[ $cK ] ) ) { + + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_TASK, + 'objid' => $id, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); + + } + } + } + + // / Custom Fields + + } // / if $data + + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $this->addUpdateEventTags( - array( - 'id' => $newID, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + $confirmedExtraMeta = array(); - } + foreach ( $extraMeta as $k => $v ) { - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( - array( - 'obj_id' => $newID, - 'obj_type_id' => ZBS_TYPE_TASK, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), - ) - ); // for IA below + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - // Custom fields? + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_TASK, $id, 'extra_' . $cleanKey, $v ); - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - // any? - if (isset($data[$cK])){ + } + } - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_TASK, - 'objid' => $newID, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // UPDATING CONTACT + if ( ! $silentInsert ) { + + // catch dirty flag (update of status) (note, after update_post_meta - as separate) + // if (isset($_POST['zbse_status_dirtyflag']) && $_POST['zbse_status_dirtyflag'] == "1"){ + // actually here, it's set above + /* + WH not sure if used for this obj: + if (isset($statusChange) && is_array($statusChange)){ + + // status has changed + + // IA + zeroBSCRM_FireInternalAutomator('event.status.update',array( + 'id'=>$id, + 'againstid' => $id, + 'userMeta'=> $dataArr, + 'from' => $statusChange['from'], + 'to' => $statusChange['to'] + )); + + } */ + + // IA General event update (2.87+) + zeroBSCRM_FireInternalAutomator( + 'event.update', + array( + 'id' => $id, + 'data' => $data, + 'extsource' => $approvedExternalSource, + 'againstids' => $againstIDs, + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); - } + } - } + // Successfully updated - Return id + return $id; - // / Custom Fields + } else { - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - $confirmedExtraMeta = array(); + // FAILED update + return false; - foreach ($extraMeta as $k => $v){ + } + } else { - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['events'], + $dataArr, + $typeArr + ) > 0 ) { - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_TASK,$newID,'extra_'.$cleanKey,$v); + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + // defaults for IA below + $approvedExternalSource = ''; + $againstIDs = array( + 'contacts' => array(), + 'companies' => array(), + ); - } + // Event Reminders ==== - } + // event reminder work? + if ( isset( $data['reminders'] ) && is_array( $data['reminders'] ) ) { + // if array passed, update, even if removing + if ( count( $data['reminders'] ) > 0 ) { + // passed, for now this is BRUTAL and just clears old ones + readds + // once live, discuss how to refactor to be less brutal. + // for now will be fine if you LOAD reminders, edit, addUpdate, -> don't recreate them then rejam in expecting it to know how to deal with :) + // (in which case reminders sent already might get resent, but that's if not following this note ^) - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT - if (!$silentInsert){ + // delete all reminders + $this->DAL()->eventreminders->deleteEventRemindersForEvent( array( 'eventID' => $newID ) ); - #} Add to automator - zeroBSCRM_FireInternalAutomator('event.new',array( - 'id'=>$newID, - 'data'=>$data, - 'extsource'=>$approvedExternalSource, - 'againstids'=>$againstIDs, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); + // addupdate each + foreach ( $data['reminders'] as $reminder ) { - } - - return $newID; + // no point in this: + // slight rejig of passed so works cleanly with data array style + // $reminderID = false; if (isset($reminder['ID'])) $reminderID = $reminder['ID']; + $reminderID = false; - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); + // if 'event' isn't set, add this event id + // actually hard set.. if (!isset($reminder['event'])) + $reminder['event'] = $newID; - #} Failed to Insert - return false; + $this->DAL()->eventreminders->addUpdateEventreminder( + array( + 'id' => $reminderID, + 'data' => $reminder, + ) + ); - } + } + } else { + + // delete all reminders + $this->DAL()->eventreminders->deleteEventRemindersForEvent( array( 'eventID' => $newID ) ); + + } + } + + // / Event Reminders ==== + + // OBJ LINKS - to contacts/companies + $this->addUpdateObjectLinks( $newID, $data['contacts'], ZBS_TYPE_CONTACT ); + $this->addUpdateObjectLinks( $newID, $data['companies'], ZBS_TYPE_COMPANY ); + // IA also gets 'againstid' historically, but we'll pass as 'against id's' + $againstIDs = array( + 'contacts' => $data['contacts'], + 'companies' => $data['companies'], + ); + + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { + + $this->addUpdateEventTags( + array( + 'id' => $newID, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); + + } + + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $newID, + 'obj_type_id' => ZBS_TYPE_TASK, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below + + // Custom fields? + + #} Cycle through + add/update if set + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { + + // any? + if ( isset( $data[ $cK ] ) ) { + + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_TASK, + 'objid' => $newID, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); - } + } + } + } - return false; + // / Custom Fields - } + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - /** - * adds or updates a event's tags - * ... this is really just a wrapper for addUpdateObjectTags - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateEventTags($args=array()){ + $confirmedExtraMeta = array(); - global $ZBSCRM_t,$wpdb; + foreach ( $extraMeta as $k => $v ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - 'id' => -1, - - // generic pass-through (array of tag strings or tag IDs): - 'tag_input' => -1, + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_TASK, $newID, 'extra_' . $cleanKey, $v ); - // or either specific: - 'tagIDs' => -1, - 'tags' => -1, + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - 'mode' => 'append' + } + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // NEW CONTACT + if ( ! $silentInsert ) { - #} ========== CHECK FIELDS ============ + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'event.new', + array( + 'id' => $newID, + 'data' => $data, + 'extsource' => $approvedExternalSource, + 'againstids' => $againstIDs, + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; + } - #} ========= / CHECK FIELDS =========== + return $newID; - return $this->DAL()->addUpdateObjectTags( - array( - 'objtype' => ZBS_TYPE_TASK, - 'objid' => $id, - 'tag_input' => $tag_input, - 'tags' => $tags, - 'tagIDs' => $tagIDs, - 'mode' => $mode - ) - ); + } else { - } + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); + #} Failed to Insert + return false; + } + } - /** - * mark event as comoplete - * - * @param int id Event ID - * @param int (Bool) completion status -1 or 1 - * - * @return bool - */ - public function setEventCompleteness($id=-1,$status=-1){ + return false; + } - global $zbs; + /** + * adds or updates a event's tags + * ... this is really just a wrapper for addUpdateObjectTags + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateEventTags( $args = array() ) { - $id = (int)$id; + global $ZBSCRM_t, $wpdb; - if ($id > 0){ + #} ============ LOAD ARGS ============= + $defaultArgs = array( - return $this->addUpdateEvent(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbse_complete','val' => $status,'type' => '%d') - ))); + 'id' => -1, - } + // generic pass-through (array of tag strings or tag IDs): + 'tag_input' => -1, - return false; - - } + // or either specific: + 'tagIDs' => -1, + 'tags' => -1, + 'mode' => 'append', - /** - * deletes a event object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteEvent($args=array()){ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - global $ZBSCRM_t,$wpdb,$zbs; + #} ========== CHECK FIELDS ============ - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } - 'id' => -1, - 'saveOrphans' => false + #} ========= / CHECK FIELDS =========== + + return $this->DAL()->addUpdateObjectTags( + array( + 'objtype' => ZBS_TYPE_TASK, + 'objid' => $id, + 'tag_input' => $tag_input, + 'tags' => $tags, + 'tagIDs' => $tagIDs, + 'mode' => $mode, + ) + ); + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + /** + * mark event as comoplete + * + * @param int id Event ID + * @param int (Bool) completion status -1 or 1 + * + * @return bool + */ + public function setEventCompleteness( $id = -1, $status = -1 ) { - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ + global $zbs; - // delete any tag links - $this->DAL()->deleteTagObjLinks(array( + $id = (int) $id; + + if ( $id > 0 ) { + + return $this->addUpdateEvent( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbse_complete', + 'val' => $status, + 'type' => '%d', + ), + ), + ) + ); - 'objtype' => ZBS_TYPE_TASK, - 'objid' => $id - )); + } - // delete any objlinks - $this->addUpdateObjectLinks($id,'unset',ZBS_TYPE_TASK); + return false; + } - // delete any reminders - $this->DAL()->eventreminders->deleteEventRemindersForEvent(array('eventID'=>$id)); + /** + * deletes a event object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteEvent( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'saveOrphans' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - // delete any external source information - $this->DAL()->delete_external_sources( array( + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - 'obj_type' => ZBS_TYPE_TASK, - 'obj_id' => $id, - 'obj_source' => 'all', + // delete orphans? + if ( $saveOrphans === false ) { - )); + // delete any tag links + $this->DAL()->deleteTagObjLinks( + array( - } - - $del = zeroBSCRM_db2_deleteGeneric($id,'events'); + 'objtype' => ZBS_TYPE_TASK, + 'objid' => $id, + ) + ); - #} Add to automator - zeroBSCRM_FireInternalAutomator('event.delete',array( - 'id'=>$id, - 'saveOrphans'=>$saveOrphans - )); + // delete any objlinks + $this->addUpdateObjectLinks( $id, 'unset', ZBS_TYPE_TASK ); - return $del; + // delete any reminders + $this->DAL()->eventreminders->deleteEventRemindersForEvent( array( 'eventID' => $id ) ); - } + // delete any external source information + $this->DAL()->delete_external_sources( + array( - return false; + 'obj_type' => ZBS_TYPE_TASK, + 'obj_id' => $id, + 'obj_source' => 'all', - } + ) + ); - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array event (clean obj) - */ - private function tidy_event($obj=false,$withCustomFields=false){ + } - $res = false; + $del = zeroBSCRM_db2_deleteGeneric( $id, 'events' ); - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = $obj->zbs_owner; + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'event.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); - - $res['title'] = $this->stripSlashes($obj->zbse_title); - $res['desc'] = $this->stripSlashes($obj->zbse_desc); - $res['start'] = (int)$obj->zbse_start; - $res['start_date'] = (isset($obj->zbse_start) && $obj->zbse_start > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbse_start) : false; - $res['end'] = (int)$obj->zbse_end; - $res['end_date'] = (isset($obj->zbse_end) && $obj->zbse_end > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbse_end) : false; - $res['complete'] = (int)$this->stripSlashes($obj->zbse_complete); - $res['show_on_portal'] = (int)$obj->zbse_show_on_portal; - $res['show_on_cal'] = (int)$obj->zbse_show_on_cal; - $res['created'] = (int)$obj->zbse_created; - $res['created_date'] = (isset($obj->zbse_created) && $obj->zbse_created > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbse_created) : false; - $res['lastupdated'] = (int)$obj->zbse_lastupdated; - $res['lastupdated_date'] = (isset($obj->zbse_lastupdated) && $obj->zbse_lastupdated > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbse_lastupdated) : false; - - - // custom fields - tidy any that are present: - if ($withCustomFields) $res = $this->tidyAddCustomFields(ZBS_TYPE_TASK,$obj,$res,false); + return $del; - } + } + return false; + } - return $res; + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array event (clean obj) + */ + private function tidy_event( $obj = false, $withCustomFields = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = $obj->zbs_owner; + + $res['title'] = $this->stripSlashes( $obj->zbse_title ); + $res['desc'] = $this->stripSlashes( $obj->zbse_desc ); + $res['start'] = (int) $obj->zbse_start; + $res['start_date'] = ( isset( $obj->zbse_start ) && $obj->zbse_start > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbse_start ) : false; + $res['end'] = (int) $obj->zbse_end; + $res['end_date'] = ( isset( $obj->zbse_end ) && $obj->zbse_end > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbse_end ) : false; + $res['complete'] = (int) $this->stripSlashes( $obj->zbse_complete ); + $res['show_on_portal'] = (int) $obj->zbse_show_on_portal; + $res['show_on_cal'] = (int) $obj->zbse_show_on_cal; + $res['created'] = (int) $obj->zbse_created; + $res['created_date'] = ( isset( $obj->zbse_created ) && $obj->zbse_created > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbse_created ) : false; + $res['lastupdated'] = (int) $obj->zbse_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbse_lastupdated ) && $obj->zbse_lastupdated > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbse_lastupdated ) : false; + + // custom fields - tidy any that are present: + if ( $withCustomFields ) { + $res = $this->tidyAddCustomFields( ZBS_TYPE_TASK, $obj, $res, false ); + } + } + return $res; + } - } + /** + * Wrapper, use $this->getEventMeta($contactID,$key) for easy retrieval of singular event + * Simplifies $this->getMeta + * + * @param int objtype + * @param int objid + * @param string key + * + * @return array event meta result + */ + public function getEventMeta( $id = -1, $key = '', $default = false ) { + global $zbs; - /** - * Wrapper, use $this->getEventMeta($contactID,$key) for easy retrieval of singular event - * Simplifies $this->getMeta - * - * @param int objtype - * @param int objid - * @param string key - * - * @return array event meta result - */ - public function getEventMeta($id=-1,$key='',$default=false){ + if ( ! empty( $key ) ) { - global $zbs; + return $this->DAL()->getMeta( + array( - if (!empty($key)){ + 'objtype' => ZBS_TYPE_TASK, + 'objid' => $id, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, + 'ignoreowner' => true, // for now !! - return $this->DAL()->getMeta(array( + ) + ); - 'objtype' => ZBS_TYPE_TASK, - 'objid' => $id, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default, - 'ignoreowner' => true // for now !! + } - )); + return $default; + } - } + /** + * Returns an ownerid against a event + * + * @param int id event ID + * + * @return int event owner id + */ + public function getEventOwner( $id = -1 ) { - return $default; - } + global $zbs; + $id = (int) $id; - - /** - * Returns an ownerid against a event - * - * @param int id event ID - * - * @return int event owner id - */ - public function getEventOwner($id=-1){ + if ( $id > 0 ) { - global $zbs; + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_TASK, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); - $id = (int)$id; + } - if ($id > 0){ - - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_TASK, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); - - } - - return false; - - } - - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * This does so based on the objectModel! - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - private function db_ready_event($obj=false){ + return false; + } - // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * This does so based on the objectModel! + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + private function db_ready_event( $obj = false ) { - } + // use the generic? (override here if necessary) + return $this->db_ready_obj( $obj ); + } - /** - * Takes full object and makes a "list view" boiled down version - * Used to generate listview objs - * - * @param array $obj (clean obj) - * - * @return array (listview ready obj) - */ - public function listViewObj($event=false,$columnsRequired=array()){ + /** + * Takes full object and makes a "list view" boiled down version + * Used to generate listview objs + * + * @param array $obj (clean obj) + * + * @return array (listview ready obj) + */ + public function listViewObj( $event = false, $columnsRequired = array() ) { - if (is_array($event) && isset($event['id'])){ + if ( is_array( $event ) && isset( $event['id'] ) ) { - $resArr = $event; + $resArr = $event; - #} Convert contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer - if ( array_key_exists( 'contact', $event ) ) { - $resArr['contact'] = zeroBSCRM_getSimplyFormattedContact($event['contact'], (in_array('assignedobj', $columnsRequired))); - } + #} Convert contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer + if ( array_key_exists( 'contact', $event ) ) { + $resArr['contact'] = zeroBSCRM_getSimplyFormattedContact( $event['contact'], ( in_array( 'assignedobj', $columnsRequired ) ) ); + } - #} Convert company arr into list-view-digestable 'customer'// & unset contact for leaner data transfer - if ( array_key_exists( 'company', $event ) ) { - $resArr['company'] = zeroBSCRM_getSimplyFormattedCompany($event['company'], (in_array('assignedobj', $columnsRequired))); - } - - return $resArr; + #} Convert company arr into list-view-digestable 'customer'// & unset contact for leaner data transfer + if ( array_key_exists( 'company', $event ) ) { + $resArr['company'] = zeroBSCRM_getSimplyFormattedCompany( $event['company'], ( in_array( 'assignedobj', $columnsRequired ) ) ); + } - } + return $resArr; - return false; + } - } + return false; + } - // =========== / EVENT ======================================================= - // =============================================================================== + // =========== / EVENT ======================================================= + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Forms.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Forms.php index ba4712656a70..2cd6859f2fe9 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Forms.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Forms.php @@ -1,5 +1,6 @@ -> Forms -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Forms + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_forms extends zbsDAL_ObjectLayer { - - protected $objectType = ZBS_TYPE_FORM; - protected $objectDBPrefix = 'zbsf_'; - protected $objectModel = array( - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'title' => array( - // db model: - 'fieldname' => 'zbsf_title', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Form Title', - 'placeholder'=>'', - 'essential' => true, - 'max_len' => 200 - ), - 'style' => array('fieldname' => 'zbsf_style', 'format' => 'str'), - 'views' => array('fieldname' => 'zbsf_views', 'format' => 'int'), - 'conversions' => array('fieldname' => 'zbsf_conversions', 'format' => 'int'), - 'label_header' => array( - // db model: - 'fieldname' => 'zbsf_label_header', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Header', - 'placeholder'=> 'Want to find out more?', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'label_subheader' => array( - // db model: - 'fieldname' => 'zbsf_label_subheader', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Sub Header', - 'placeholder'=> 'Drop us a line. We follow up on all contacts', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'label_firstname' => array( - // db model: - 'fieldname' => 'zbsf_label_firstname', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'First Name Placeholder', - 'placeholder'=> 'First Name', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'label_lastname' => array( - // db model: - 'fieldname' => 'zbsf_label_lastname', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Last Name Placeholder', - 'placeholder'=> 'Last Name', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'label_email' => array( - // db model: - 'fieldname' => 'zbsf_label_email', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Email Placeholder', - 'placeholder'=> 'Email', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'label_message' => array( - // db model: - 'fieldname' => 'zbsf_label_message', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Message Placeholder', - 'placeholder'=> 'Your Message', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'label_button' => array( - // db model: - 'fieldname' => 'zbsf_label_button', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Submit Button', - 'placeholder'=> 'Submit', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'label_successmsg' => array( - // db model: - 'fieldname' => 'zbsf_label_successmsg', 'format' => 'str', - // output model - 'input_type' => 'textarea', - 'label' => 'Success Message', - 'placeholder'=> 'Thanks. We will be in touch.', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'label_spammsg' => array( - // db model: - 'fieldname' => 'zbsf_label_spammsg', 'format' => 'str', - // output model - 'input_type' => 'textarea', - 'label' => 'Spam Message', - 'placeholder'=> 'We will not send you spam. Our team will be in touch within 24 to 48 hours Mon-Fri (but often much quicker)', - 'nocolumn'=>true, - 'max_len' => 200 - ), - 'include_terms_check' => array( - // db model: - 'fieldname' => 'zbsf_include_terms_check', 'format' => 'bool', - /* not live in v3.0, to add v3.1+ - // output model - 'input_type' => 'checkbox', - 'label' => 'Include "Terms and Conditions Check"', - 'placeholder'=>'', - 'nocolumn'=>true */ - ), - 'terms_url' => array( - // db model: - 'fieldname' => 'zbsf_terms_url', 'format' => 'str', - /* not live in v3.0, to add v3.1+ - // output model - 'input_type' => 'text', - 'label' => 'Terms and Conditions URL', - 'placeholder'=>'', - 'nocolumn'=>true, - 'max_len' => 200 */ - ), - 'redir_url' => array( - // db model: - 'fieldname' => 'zbsf_redir_url', 'format' => 'str', - /* not live in v3.0, to add v3.1+ - // output model - 'input_type' => 'text', - 'label' => 'Redirection URL', - 'placeholder'=>'', - 'nocolumn'=>true, - 'max_len' => 200 */ - ), - 'font' => array('fieldname' => 'zbsf_font', 'format' => 'str'), - 'colour_bg' => array('fieldname' => 'zbsf_colour_bg', 'format' => 'str'), - 'colour_font' => array('fieldname' => 'zbsf_colour_font', 'format' => 'str'), - 'colour_emphasis' => array('fieldname' => 'zbsf_colour_emphasis', 'format' => 'str'), - 'created' => array('fieldname' => 'zbsf_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsf_lastupdated', 'format' => 'uts'), - - ); - - - function __construct($args=array()) { - - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - - } - - - - // =============================================================================== - // =========== FORM =========================================================== - - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ - - return $this->getForm($ID); - - } - - // generic get (by ID list) - // Super simplistic wrapper used by MVP Export v3.0 - public function getIDList($IDs=false){ - - return $this->getForms(array( - 'inArr' => $IDs, - 'page' => -1, - 'perPage' => -1 - )); - - } - - // generic get (EVERYTHING) - // expect heavy load! - public function getAll($IDs=false){ - - return $this->getForms(array( - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => -1, - 'perPage' => -1, - )); - - } - - // generic get count of (EVERYTHING) - public function getFullCount(){ - - return $this->getForms(array( - 'count' => true, - 'page' => -1, - 'perPage' => -1, - )); - - } - - /** - * returns full form line +- details - * - * @param int id form id - * @param array $args Associative array of arguments - * - * @return array form object - */ - public function getForm($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - // with what? - 'withTags' => false, - 'withOwner' => false, - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_FORM), // this'll let you not-check the owner of obj - - // returns scalar ID of line - 'onlyID' => false, - - 'fields' => false // false = *, array = fieldnames - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check ID - $id = (int)$id; - if ( - (!empty($id) && $id > 0) - || - (!empty($email)) - || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ - - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; - - - #} ============= PRE-QUERY ============ - - $selector = 'form.*'; + protected $objectType = ZBS_TYPE_FORM; + protected $objectDBPrefix = 'zbsf_'; + protected $objectModel = array( + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'title' => array( + // db model: + 'fieldname' => 'zbsf_title', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Form Title', + 'placeholder' => '', + 'essential' => true, + 'max_len' => 200, + ), + 'style' => array( + 'fieldname' => 'zbsf_style', + 'format' => 'str', + ), + 'views' => array( + 'fieldname' => 'zbsf_views', + 'format' => 'int', + ), + 'conversions' => array( + 'fieldname' => 'zbsf_conversions', + 'format' => 'int', + ), + 'label_header' => array( + // db model: + 'fieldname' => 'zbsf_label_header', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Header', + 'placeholder' => 'Want to find out more?', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'label_subheader' => array( + // db model: + 'fieldname' => 'zbsf_label_subheader', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Sub Header', + 'placeholder' => 'Drop us a line. We follow up on all contacts', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'label_firstname' => array( + // db model: + 'fieldname' => 'zbsf_label_firstname', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'First Name Placeholder', + 'placeholder' => 'First Name', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'label_lastname' => array( + // db model: + 'fieldname' => 'zbsf_label_lastname', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Last Name Placeholder', + 'placeholder' => 'Last Name', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'label_email' => array( + // db model: + 'fieldname' => 'zbsf_label_email', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Email Placeholder', + 'placeholder' => 'Email', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'label_message' => array( + // db model: + 'fieldname' => 'zbsf_label_message', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Message Placeholder', + 'placeholder' => 'Your Message', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'label_button' => array( + // db model: + 'fieldname' => 'zbsf_label_button', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Submit Button', + 'placeholder' => 'Submit', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'label_successmsg' => array( + // db model: + 'fieldname' => 'zbsf_label_successmsg', + 'format' => 'str', + // output model + 'input_type' => 'textarea', + 'label' => 'Success Message', + 'placeholder' => 'Thanks. We will be in touch.', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'label_spammsg' => array( + // db model: + 'fieldname' => 'zbsf_label_spammsg', + 'format' => 'str', + // output model + 'input_type' => 'textarea', + 'label' => 'Spam Message', + 'placeholder' => 'We will not send you spam. Our team will be in touch within 24 to 48 hours Mon-Fri (but often much quicker)', + 'nocolumn' => true, + 'max_len' => 200, + ), + 'include_terms_check' => array( + // db model: + 'fieldname' => 'zbsf_include_terms_check', + 'format' => 'bool', + /* + not live in v3.0, to add v3.1+ + // output model + 'input_type' => 'checkbox', + 'label' => 'Include "Terms and Conditions Check"', + 'placeholder'=>'', + 'nocolumn'=>true */ + ), + 'terms_url' => array( + // db model: + 'fieldname' => 'zbsf_terms_url', + 'format' => 'str', + /* + not live in v3.0, to add v3.1+ + // output model + 'input_type' => 'text', + 'label' => 'Terms and Conditions URL', + 'placeholder'=>'', + 'nocolumn'=>true, + 'max_len' => 200 */ + ), + 'redir_url' => array( + // db model: + 'fieldname' => 'zbsf_redir_url', + 'format' => 'str', + /* + not live in v3.0, to add v3.1+ + // output model + 'input_type' => 'text', + 'label' => 'Redirection URL', + 'placeholder'=>'', + 'nocolumn'=>true, + 'max_len' => 200 */ + ), + 'font' => array( + 'fieldname' => 'zbsf_font', + 'format' => 'str', + ), + 'colour_bg' => array( + 'fieldname' => 'zbsf_colour_bg', + 'format' => 'str', + ), + 'colour_font' => array( + 'fieldname' => 'zbsf_colour_font', + 'format' => 'str', + ), + 'colour_emphasis' => array( + 'fieldname' => 'zbsf_colour_emphasis', + 'format' => 'str', + ), + 'created' => array( + 'fieldname' => 'zbsf_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsf_lastupdated', + 'format' => 'uts', + ), + + ); + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + } + + // =============================================================================== + // =========== FORM =========================================================== + + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { + + return $this->getForm( $ID ); + } + + // generic get (by ID list) + // Super simplistic wrapper used by MVP Export v3.0 + public function getIDList( $IDs = false ) { + + return $this->getForms( + array( + 'inArr' => $IDs, + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + // generic get (EVERYTHING) + // expect heavy load! + public function getAll( $IDs = false ) { + + return $this->getForms( + array( + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + // generic get count of (EVERYTHING) + public function getFullCount() { + + return $this->getForms( + array( + 'count' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + /** + * returns full form line +- details + * + * @param int id form id + * @param array $args Associative array of arguments + * + * @return array form object + */ + public function getForm( $id = -1, $args = array() ) { + + global $zbs; + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // with what? + 'withTags' => false, + 'withOwner' => false, + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_FORM ), // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + 'fields' => false, // false = *, array = fieldnames + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + #} Check ID + $id = (int) $id; + if ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $email ) ) + || + ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) + ) { + + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $extraSelect = ''; + + #} ============= PRE-QUERY ============ + + $selector = 'form.*'; if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $selector = ''; - - // always needs id, so add if not present - if (!in_array('ID',$fields)) $selector = 'form.ID'; - - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'form.'.$f; - } - } else if ($onlyID){ - $selector = 'form.ID'; - } - - #} ============ / PRE-QUERY =========== - - - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['forms'].' as form'; - #} ============= WHERE ================ - - if (!empty($id) && $id > 0){ - - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); - - } - - #} ============ / WHERE ============== - - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE - - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); - - try { - - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $this->catchSQLError($e); - - } - - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { - - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID) return $potentialRes->ID; - - // tidy - if (is_array($fields)){ - // guesses fields based on table col names - $res = $this->lazyTidyGeneric($potentialRes); - } else { - // proper tidy - $res = $this->tidy_form($potentialRes);//$withCustomFields - } - - if ($withTags){ - - // add all tags lines - $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_FORM,'objid'=>$potentialRes->ID)); - - } + $selector = ''; - return $res; + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'form.ID'; + } - } + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'form.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'form.ID'; + } - } // / if ID + #} ============ / PRE-QUERY =========== - return false; + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['forms'] . ' as form'; + #} ============= WHERE ================ - } + if ( ! empty( $id ) && $id > 0 ) { - /** - * returns form detail lines - * - * @param array $args Associative array of arguments - * - * @return array of form lines - */ - public function getForms($args=array()){ + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); + + } - global $zbs; + #} ============ / WHERE ============== + + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership + + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); + + try { + + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); + + } catch ( Exception $e ) { + + #} General SQL Err + $this->catchSQLError( $e ); + + } + + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { + + #} Has results, tidy + return + + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } + + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_form( $potentialRes );// $withCustomFields + } + + if ( $withTags ) { + + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_FORM, + 'objid' => $potentialRes->ID, + ) + ); + + } + + return $res; + + } + } // / if ID + + return false; + } + + /** + * returns form detail lines + * + * @param array $args Associative array of arguments + * + * @return array of form lines + */ + public function getForms( $args = array() ) { + + global $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => '', // searches title + 'inArr' => false, + 'isTagged' => false, // 1x INT OR array(1,2,3) + 'isNotTagged' => false, // 1x INT OR array(1,2,3) + 'ownedBy' => false, + 'olderThan' => false, // uts + 'newerThan' => false, // uts + + // returns + 'count' => false, + 'withTags' => false, + 'withOwner' => false, + 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 100, + 'whereCase' => 'AND', // DEFAULT = AND + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_FORM ), // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - #} ============ LOAD ARGS ============= - $defaultArgs = array( + global $ZBSCRM_t, $wpdb, $zbs; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches title - 'inArr' => false, - 'isTagged' => false, // 1x INT OR array(1,2,3) - 'isNotTagged' => false, // 1x INT OR array(1,2,3) - 'ownedBy' => false, - 'olderThan' => false, // uts - 'newerThan' => false, // uts + #} ============= PRE-QUERY ============ + + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); - // returns - 'count' => false, - 'withTags' => false, - 'withOwner' => false, - 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) + #} If just count, turn off any extra gumpf + if ( $count ) { + $withTags = false; + $withOwner = false; + } - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 100, - 'whereCase' => 'AND', // DEFAULT = AND + #} If onlyColumns, validate + if ( $onlyColumns ) { - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_FORM), // this'll let you not-check the owner of obj + #} onlyColumns build out a field arr + if ( is_array( $onlyColumns ) && count( $onlyColumns ) > 0 ) { + $onlyColumnsFieldArr = array(); + foreach ( $onlyColumns as $col ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + // find db col key from field key (e.g. fname => zbsc_fname) + $dbCol = ''; + if ( isset( $this->objectModel[ $col ] ) && isset( $this->objectModel[ $col ]['fieldname'] ) ) { + $dbCol = $this->objectModel[ $col ]['fieldname']; + } - global $ZBSCRM_t,$wpdb,$zbs; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; + if ( ! empty( $dbCol ) ) { - #} ============= PRE-QUERY ============ + $onlyColumnsFieldArr[ $dbCol ] = $col; - #} Capitalise this - $sortOrder = strtoupper($sortOrder); + } + } + } - #} If just count, turn off any extra gumpf - if ($count) { - $withTags = false; - $withOwner = false; - } + // if legit cols: + if ( isset( $onlyColumnsFieldArr ) && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - #} If onlyColumns, validate - if ($onlyColumns){ + $onlyColumns = true; - #} onlyColumns build out a field arr - if (is_array($onlyColumns) && count($onlyColumns) > 0){ + // If onlyColumns, turn off extras + $withTags = false; + $withOwner = false; - $onlyColumnsFieldArr = array(); - foreach ($onlyColumns as $col){ + } else { - // find db col key from field key (e.g. fname => zbsc_fname) - $dbCol = ''; if (isset($this->objectModel[$col]) && isset($this->objectModel[$col]['fieldname'])) $dbCol = $this->objectModel[$col]['fieldname']; + // deny + $onlyColumns = false; - if (!empty($dbCol)){ + } + } - $onlyColumnsFieldArr[$dbCol] = $col; + #} ============ / PRE-QUERY =========== - } + #} Build query + $query = 'SELECT form.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['forms'] . ' as form' . $joinQ; - } + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(form.ID) FROM ' . $ZBSCRM_t['forms'] . ' as form' . $joinQ; + } - } + #} onlyColumns override + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - // if legit cols: - if (isset($onlyColumnsFieldArr) && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + $columnStr = ''; + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - $onlyColumns = true; - - // If onlyColumns, turn off extras - $withTags = false; - $withOwner = false; + if ( ! empty( $columnStr ) ) { + $columnStr .= ','; + } + // this presumes str is db-safe? could do with sanitation? + $columnStr .= $colDBKey; - } else { + } - // deny - $onlyColumns = false; + $query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['forms'] . ' as form' . $joinQ; - } + } + #} ============= WHERE ================ - } + #} Add Search phrase + if ( ! empty( $searchPhrase ) ) { - #} ============ / PRE-QUERY =========== + // search? - ALL THESE COLS should probs have index of FULLTEXT in db? + $searchWheres = array(); + $searchWheres['search_ID'] = array( 'ID', '=', '%d', $searchPhrase ); + $searchWheres['search_title'] = array( 'zbsf_title', 'LIKE', '%s', '%' . $searchPhrase . '%' ); - #} Build query - $query = "SELECT form.*".$extraSelect." FROM ".$ZBSCRM_t['forms'].' as form'.$joinQ; + // 3.0.13 - Added ability to search custom fields (optionally) + $customFieldSearch = zeroBSCRM_getSetting( 'customfieldsearch' ); + if ( $customFieldSearch == 1 ) { - #} Count override - if ($count) $query = "SELECT COUNT(form.ID) FROM ".$ZBSCRM_t['forms'].' as form'.$joinQ; + // simplistic add + // NOTE: This IGNORES ownership of custom field lines. + $searchWheres['search_customfields'] = array( 'ID', 'IN', '(SELECT zbscf_objid FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objval LIKE %s AND zbscf_objtype = ' . ZBS_TYPE_FORM . ')', '%' . $searchPhrase . '%' ); - #} onlyColumns override - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + } - $columnStr = ''; - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + // This generates a query like 'zbsf_fname LIKE %s OR zbsf_lname LIKE %s', + // which we then need to include as direct subquery (below) in main query :) + $searchQueryArr = $this->buildWheres( $searchWheres, '', array(), 'OR', false ); - if (!empty($columnStr)) $columnStr .= ','; - // this presumes str is db-safe? could do with sanitation? - $columnStr .= $colDBKey; + if ( is_array( $searchQueryArr ) && isset( $searchQueryArr['where'] ) && ! empty( $searchQueryArr['where'] ) ) { - } + // add it + $wheres['direct'][] = array( '(' . $searchQueryArr['where'] . ')', $searchQueryArr['params'] ); - $query = "SELECT ".$columnStr." FROM ".$ZBSCRM_t['forms'].' as form'.$joinQ; + } + } - } + #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { - #} ============= WHERE ================ + // clean for ints + $inArrChecked = array(); + foreach ( $inArr as $x ) { + $inArrChecked[] = (int) $x; } - #} Add Search phrase - if (!empty($searchPhrase)){ + // add where + $wheres['inarray'] = array( 'ID', 'IN', '(' . implode( ',', $inArrChecked ) . ')' ); - // search? - ALL THESE COLS should probs have index of FULLTEXT in db? - $searchWheres = array(); - $searchWheres['search_ID'] = array('ID','=','%d',$searchPhrase); - $searchWheres['search_title'] = array('zbsf_title','LIKE','%s','%'.$searchPhrase.'%'); + } - // 3.0.13 - Added ability to search custom fields (optionally) - $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); - if ($customFieldSearch == 1){ - - // simplistic add - // NOTE: This IGNORES ownership of custom field lines. - $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE zbscf_objval LIKE %s AND zbscf_objtype = ".ZBS_TYPE_FORM.")",'%'.$searchPhrase.'%'); + #} Owned by + if ( ! empty( $ownedBy ) && $ownedBy > 0 ) { - } + // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) + // but this is only here until MIGRATED to db2 globally + // $wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); + // Use obj links now + $wheres['ownedBy'] = array( 'zbs_owner', '=', '%s', $ownedBy ); - // This generates a query like 'zbsf_fname LIKE %s OR zbsf_lname LIKE %s', - // which we then need to include as direct subquery (below) in main query :) - $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - - if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ - - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); - - } - - } - - #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) - if (is_array($inArr) && count($inArr) > 0){ - - // clean for ints - $inArrChecked = array(); foreach ($inArr as $x){ $inArrChecked[] = (int)$x; } - - // add where - $wheres['inarray'] = array('ID','IN','('.implode(',',$inArrChecked).')'); - - } - - #} Owned by - if (!empty($ownedBy) && $ownedBy > 0){ - - // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) - // but this is only here until MIGRATED to db2 globally - //$wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); - // Use obj links now - $wheres['ownedBy'] = array('zbs_owner','=','%s',$ownedBy); - - } + } // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed // quick addition for mike @@ -566,992 +682,1056 @@ public function getForms($args=array()){ if ( ! empty( $newerThan ) && $newerThan > 0 ) $wheres['newerThan'] = array( 'zbsf_created', '>=', '%d', $newerThan ); // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed - #} Is Tagged (expects 1 tag ID OR array) + #} Is Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isTagged) && count($isTagged) == 1) $isTagged = $isTagged[0]; + // catch 1 item arr + if ( is_array( $isTagged ) && count( $isTagged ) == 1 ) { + $isTagged = $isTagged[0]; + } if ( ! empty( $isTagged ) && ! is_array( $isTagged ) && $isTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = form.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_FORM,$isTagged)); + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = form.ID AND zbstl_tagid = %d) > 0)', array( ZBS_TYPE_FORM, $isTagged ) ); - } else if (is_array($isTagged) && count($isTagged) > 0){ + } elseif ( is_array( $isTagged ) && count( $isTagged ) > 0 ) { - // foreach in array :) - $tagStr = ''; - foreach ($isTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + // foreach in array :) + $tagStr = ''; + foreach ( $isTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = form.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_FORM,$tagStr)); + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = form.ID AND zbstl_tagid IN (%s)) > 0)', array( ZBS_TYPE_FORM, $tagStr ) ); - } - #} Is NOT Tagged (expects 1 tag ID OR array) + } + } + #} Is NOT Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isNotTagged) && count($isNotTagged) == 1) $isNotTagged = $isNotTagged[0]; + // catch 1 item arr + if ( is_array( $isNotTagged ) && count( $isNotTagged ) == 1 ) { + $isNotTagged = $isNotTagged[0]; + } if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = form.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_FORM,$isNotTagged)); + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = form.ID AND zbstl_tagid = %d) = 0)', array( ZBS_TYPE_FORM, $isNotTagged ) ); - } else if (is_array($isNotTagged) && count($isNotTagged) > 0){ + } elseif ( is_array( $isNotTagged ) && count( $isNotTagged ) > 0 ) { - // foreach in array :) - $tagStr = ''; - foreach ($isNotTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + // foreach in array :) + $tagStr = ''; + foreach ( $isNotTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = form.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_FORM,$tagStr)); + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = form.ID AND zbstl_tagid IN (%s)) = 0)', array( ZBS_TYPE_FORM, $tagStr ) ); - } + } + } - #} ============ / WHERE =============== + #} ============ / WHERE =============== - #} ============ SORT ============== + #} ============ SORT ============== - // Obj Model based sort conversion - // converts 'addr1' => 'zbsco_addr1' generically - if (isset($this->objectModel[$sortByField]) && isset($this->objectModel[$sortByField]['fieldname'])) $sortByField = $this->objectModel[$sortByField]['fieldname']; + // Obj Model based sort conversion + // converts 'addr1' => 'zbsco_addr1' generically + if ( isset( $this->objectModel[ $sortByField ] ) && isset( $this->objectModel[ $sortByField ]['fieldname'] ) ) { + $sortByField = $this->objectModel[ $sortByField ]['fieldname']; + } - #} ============ / SORT ============== + #} ============ / SORT ============== - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; + #} CHECK this + reset to default if faulty + if ( ! in_array( $whereCase, array( 'AND', 'OR' ) ) ) { + $whereCase = 'AND'; + } - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params, $whereCase ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'contact'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'contact' ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); - - try { + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); + try { - #} Catch count + return if requested - if ($count) return $wpdb->get_var($queryObj); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} Catch count + return if requested + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } - } catch (Exception $e){ + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - #} General SQL Err - $this->catchSQLError($e); + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + } - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // using onlyColumns filter? - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - // only coumns return. - $resArr = array(); - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - if (isset($resDataLine->$colDBKey)) $resArr[$colStr] = $resDataLine->$colDBKey; + // using onlyColumns filter? + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - } + // only coumns return. + $resArr = array(); + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { + if ( isset( $resDataLine->$colDBKey ) ) { + $resArr[ $colStr ] = $resDataLine->$colDBKey; + } + } + } else { - } else { - - // tidy - $resArr = $this->tidy_form($resDataLine);// $withCustomFields + // tidy + $resArr = $this->tidy_form( $resDataLine );// $withCustomFields - } + } - if ($withTags){ + if ( $withTags ) { - // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_FORM,'objid'=>$resDataLine->ID)); + // add all tags lines + $resArr['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_FORM, + 'objid' => $resDataLine->ID, + ) + ); - } + } $form_id = $resArr['id']; - $res[] = $resArr; - - } - } - - return $res; - } - - - /** - * Returns a count of forms (owned) - * - * @return int count - */ - public function getFormCount($args=array()){ - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // Search/Filtering (leave as false to ignore) - - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - $whereArr = array(); - - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_FORM, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - } - - - - /** - * adds or updates a form object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateForm($args=array()){ - - global $ZBSCRM_t,$wpdb,$zbs; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - 'owner' => -1, - - // fields (directly) - 'data' => array( - - 'title' => '', - 'style' => '', - 'views' => '', - 'conversions' => '', - 'label_header' => '', - 'label_subheader' => '', - 'label_firstname' => '', - 'label_lastname' => '', - 'label_email' => '', - 'label_message' => '', - 'label_button' => '', - 'label_successmsg' => '', - 'label_spammsg' => '', - 'include_terms_check' => '', - 'terms_url' => '', - 'redir_url' => '', - 'font' => '', - 'colour_bg' => '', - 'colour_font' => '', - 'colour_emphasis' => '', - - // tags - 'tags' => -1, // pass an array of tag ids or tag strings - 'tag_mode' => 'replace', // replace|append|remove - - // allow this to be set for MS sync etc. - 'created' => -1, - 'lastupdated' => '', - - ), - - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) - // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) - - // this function as DAL1 func did. - 'extraMeta' => -1, - 'automatorPassthrough' => -1, - - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newForm (because is migrating, not creating new :) this was -1 before - - 'do_not_update_blanks' => false // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) - - ); - - foreach ( $defaultArgs as $argK => $argV ) { - $$argK = $argV; - if ( is_array( $args ) && isset( $args[$argK] ) ) { - if ( is_array( $args[ $argK] ) ) { - $newData = $$argK; - if ( ! is_array( $newData ) ) { - $newData = array(); - } - foreach ( $args[ $argK ] as $subK => $subV ) { - $newData[$subK] = $subV; - } - $$argK = $newData; - } else { - $$argK = $args[$argK]; - } - } - } - - #} =========== / LOAD ARGS ============ - - #} ========== CHECK FIELDS ============ - - $id = (int) $id; - - // here we check that the potential owner CAN even own - if ($owner > 0 && !user_can($owner,'admin_zerobs_usr')) $owner = -1; - - // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } - - - if (is_array($limitedFields)){ - - // LIMITED UPDATE (only a few fields.) - if (!is_array($limitedFields) || count ($limitedFields) <= 0) return false; - // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; - - } else { - - // NORMAL, FULL UPDATE - - } + $res[] = $resArr; + + } + } + + return $res; + } + + /** + * Returns a count of forms (owned) + * + * @return int count + */ + public function getFormCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + + // permissions + 'ignoreowner' => true, // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + $whereArr = array(); + + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_FORM, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + } + + /** + * adds or updates a form object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateForm( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'owner' => -1, + + // fields (directly) + 'data' => array( + + 'title' => '', + 'style' => '', + 'views' => '', + 'conversions' => '', + 'label_header' => '', + 'label_subheader' => '', + 'label_firstname' => '', + 'label_lastname' => '', + 'label_email' => '', + 'label_message' => '', + 'label_button' => '', + 'label_successmsg' => '', + 'label_spammsg' => '', + 'include_terms_check' => '', + 'terms_url' => '', + 'redir_url' => '', + 'font' => '', + 'colour_bg' => '', + 'colour_font' => '', + 'colour_emphasis' => '', + + // tags + 'tags' => -1, // pass an array of tag ids or tag strings + 'tag_mode' => 'replace', // replace|append|remove + + // allow this to be set for MS sync etc. + 'created' => -1, + 'lastupdated' => '', + + ), + + 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + + // this function as DAL1 func did. + 'extraMeta' => -1, + 'automatorPassthrough' => -1, + + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newForm (because is migrating, not creating new :) this was -1 before + + 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + + ); + + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } + foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + } + $$argK = $newData; + } else { + $$argK = $args[ $argK ]; + } + } + } + + #} =========== / LOAD ARGS ============ + #} ========== CHECK FIELDS ============ - #} If no style, add it in - if (is_null($data['style']) || !isset($data['style']) || empty($data['style'])){ + $id = (int) $id; - //def - $data['style'] = 'simple'; + // here we check that the potential owner CAN even own + if ( $owner > 0 && ! user_can( $owner, 'admin_zerobs_usr' ) ) { + $owner = -1; + } - } + // if owner = -1, add current + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); } - #} ========= / CHECK FIELDS =========== + if ( is_array( $limitedFields ) ) { + // LIMITED UPDATE (only a few fields.) + if ( ! is_array( $limitedFields ) || count( $limitedFields ) <= 0 ) { + return false; + } + // REQ. ID too (can only update) + if ( empty( $id ) || $id <= 0 ) { + return false; + } + } else { - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== + // NORMAL, FULL UPDATE - // either ext source + setting, or set by the func call - if ($do_not_update_blanks){ + } - // this setting says 'don't override filled-out data with blanks' - // so here we check through any passed blanks + convert to limitedFields - // only matters if $id is set (there is somt to update not add - if (isset($id) && !empty($id) && $id > 0){ + #} If no style, add it in + if ( $data['style'] === null || ! isset( $data['style'] ) || empty( $data['style'] ) ) { - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_form($data); - //unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue - //unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) + // def + $data['style'] = 'simple'; + + } + + #} ========= / CHECK FIELDS =========== + + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== + + // either ext source + setting, or set by the func call + if ( $do_not_update_blanks ) { + + // this setting says 'don't override filled-out data with blanks' + // so here we check through any passed blanks + convert to limitedFields + // only matters if $id is set (there is somt to update not add + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { + + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_form( $data ); + // unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue + // unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - $origData = $data; //$data = array(); - $limitedData = array(); // array(array('key'=>'zbsf_x','val'=>y,'type'=>'%s')) + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbsf_x','val'=>y,'type'=>'%s')) - // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) - // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates - foreach ($dbData as $k => $v){ + // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) + // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates + foreach ( $dbData as $k => $v ) { - $intV = (int)$v; - - // only add if valuenot empty - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ - - // add to update arr - $limitedData[] = array( - 'key' => 'zbsf_'.$k, // we have to add zbsf_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbsf_'.$k) - ); - - // add to remade $data for post-update updates - $data[$k] = $v; - - } - - } - - // copy over - $limitedFields = $limitedData; - - } // / if ID - - } // / if do_not_update_blanks - - #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== - - - #} ========= BUILD DATA =========== - - $update = false; $dataArr = array(); $typeArr = array(); - - if (is_array($limitedFields)){ - - // LIMITED FIELDS - $update = true; - - // cycle through - foreach ($limitedFields as $field){ - - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } - - } - - // add update time - if (!isset($dataArr['zbsf_lastupdated'])){ $dataArr['zbsf_lastupdated'] = time(); $typeArr[] = '%d'; } - - } else { - - // FULL UPDATE/INSERT - - // UPDATE - $dataArr = array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, - - - 'zbsf_title' => $data['title'], - 'zbsf_style' => $data['style'], - 'zbsf_views' => $data['views'], - 'zbsf_conversions' => $data['conversions'], - 'zbsf_label_header' => $data['label_header'], - 'zbsf_label_subheader' => $data['label_subheader'], - 'zbsf_label_firstname' => $data['label_firstname'], - 'zbsf_label_lastname' => $data['label_lastname'], - 'zbsf_label_email' => $data['label_email'], - 'zbsf_label_message' => $data['label_message'], - 'zbsf_label_button' => $data['label_button'], - 'zbsf_label_successmsg' => $data['label_successmsg'], - 'zbsf_label_spammsg' => $data['label_spammsg'], - 'zbsf_include_terms_check' => $data['include_terms_check'], - 'zbsf_terms_url' => $data['terms_url'], - 'zbsf_redir_url' => $data['redir_url'], - 'zbsf_font' => $data['font'], - 'zbsf_colour_bg' => $data['colour_bg'], - 'zbsf_colour_font' => $data['colour_font'], - 'zbsf_colour_emphasis' => $data['colour_emphasis'], - 'zbsf_lastupdated' => time(), - - ); - - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner - - - '%s', - '%s', - '%d', - '%d', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%d', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%d', - - ); - - if (!empty($id) && $id > 0){ - - // is update - $update = true; - - } else { - - // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $typeArr[] = '%d'; - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbsf_created'] = $data['created'];$typeArr[] = '%d'; - } else { - $dataArr['zbsf_created'] = time(); $typeArr[] = '%d'; - } - - } - - } - - #} ========= / BUILD DATA =========== - - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== - - // if we're passing limitedFields we skip these, for now - // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ - - // verify uniques - if (!$this->verifyUniqueValues($data,$id)) return false; // / fails unique field verify - - // verify not_empty - if (!$this->verifyNonEmptyValues($data)) return false; // / fails empty field verify - - } - - // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks($dataArr); - - #} ========= / CHECK force_uniques & not_empty ================ - #} ============================================================ - - - #} Check if ID present - if ($update){ - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['forms'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ - - - // if passing limitedFields instead of data, we ignore the following - // this doesn't work, because data is in args default as arr - //if (isset($data) && is_array($data)){ - // so... - if (!isset($limitedFields) || !is_array($limitedFields) || $limitedFields == -1){ - - // tags - if (isset($data['tags']) && is_array($data['tags'])) { - - $this->addUpdateFormTags( - array( - 'id' => $id, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); - - } - - } // / if $data - - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; + $intV = (int) $v; + + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { + + // add to update arr + $limitedData[] = array( + 'key' => 'zbsf_' . $k, // we have to add zbsf_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbsf_' . $k ), + ); + + // add to remade $data for post-update updates + $data[ $k ] = $v; + + } + } + + // copy over + $limitedFields = $limitedData; + + } // / if ID + + } // / if do_not_update_blanks + + #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== + + #} ========= BUILD DATA =========== + + $update = false; + $dataArr = array(); + $typeArr = array(); + + if ( is_array( $limitedFields ) ) { + + // LIMITED FIELDS + $update = true; + + // cycle through + foreach ( $limitedFields as $field ) { + + // some weird case where getting empties, so added check + if ( ! empty( $field['key'] ) ) { + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } + } + + // add update time + if ( ! isset( $dataArr['zbsf_lastupdated'] ) ) { + $dataArr['zbsf_lastupdated'] = time(); + $typeArr[] = '%d'; } + } else { + + // FULL UPDATE/INSERT + + // UPDATE + $dataArr = array( + + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, + + 'zbsf_title' => $data['title'], + 'zbsf_style' => $data['style'], + 'zbsf_views' => $data['views'], + 'zbsf_conversions' => $data['conversions'], + 'zbsf_label_header' => $data['label_header'], + 'zbsf_label_subheader' => $data['label_subheader'], + 'zbsf_label_firstname' => $data['label_firstname'], + 'zbsf_label_lastname' => $data['label_lastname'], + 'zbsf_label_email' => $data['label_email'], + 'zbsf_label_message' => $data['label_message'], + 'zbsf_label_button' => $data['label_button'], + 'zbsf_label_successmsg' => $data['label_successmsg'], + 'zbsf_label_spammsg' => $data['label_spammsg'], + 'zbsf_include_terms_check' => $data['include_terms_check'], + 'zbsf_terms_url' => $data['terms_url'], + 'zbsf_redir_url' => $data['redir_url'], + 'zbsf_font' => $data['font'], + 'zbsf_colour_bg' => $data['colour_bg'], + 'zbsf_colour_font' => $data['colour_font'], + 'zbsf_colour_emphasis' => $data['colour_emphasis'], + 'zbsf_lastupdated' => time(), + + ); + + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner + + '%s', + '%s', + '%d', + '%d', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%d', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%d', + + ); + + if ( ! empty( $id ) && $id > 0 ) { + + // is update + $update = true; + + } else { + + // INSERT (get's few extra :D) + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbsf_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbsf_created'] = time(); + $typeArr[] = '%d'; + } + } + } + + #} ========= / BUILD DATA =========== + + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== + + // if we're passing limitedFields we skip these, for now + // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 + if ( ! is_array( $limitedFields ) ) { + + // verify uniques + if ( ! $this->verifyUniqueValues( $data, $id ) ) { + return false; // / fails unique field verify + } + + // verify not_empty + if ( ! $this->verifyNonEmptyValues( $data ) ) { + return false; // / fails empty field verify + } + } + + // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections + $dataArr = $this->wpdbChecks( $dataArr ); + + #} ========= / CHECK force_uniques & not_empty ================ + #} ============================================================ + + #} Check if ID present + if ( $update ) { + + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['forms'], + $dataArr, + array( // where + 'ID' => $id, + ), + $typeArr, + array( // where data types + '%d', + ) + ) !== false ) { + + // if passing limitedFields instead of data, we ignore the following + // this doesn't work, because data is in args default as arr + // if (isset($data) && is_array($data)){ + // so... + if ( ! isset( $limitedFields ) || ! is_array( $limitedFields ) || $limitedFields == -1 ) { + + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { + + $this->addUpdateFormTags( + array( + 'id' => $id, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); + + } + } // / if $data + + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $confirmedExtraMeta = array(); - - foreach ($extraMeta as $k => $v){ - - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); - - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_FORM,$id,'extra_'.$cleanKey,$v); + $confirmedExtraMeta = array(); - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + foreach ( $extraMeta as $k => $v ) { - } + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - } + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_FORM, $id, 'extra_' . $cleanKey, $v ); + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ + } + } + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // UPDATING CONTACT + if ( ! $silentInsert ) { - // IA General form update (2.87+) - zeroBSCRM_FireInternalAutomator('form.update',array( - 'id'=>$id, - 'againstid' => $id, - 'data'=> $dataArr - )); + // IA General form update (2.87+) + zeroBSCRM_FireInternalAutomator( + 'form.update', + array( + 'id' => $id, + 'againstid' => $id, + 'data' => $dataArr, + ) + ); - + } - } + // Successfully updated - Return id + return $id; - - // Successfully updated - Return id - return $id; + } else { - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - // FAILED update - return false; + // FAILED update + return false; - } + } + } else { - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['forms'], - $dataArr, - $typeArr ) > 0){ + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['forms'], + $dataArr, + $typeArr + ) > 0 ) { - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { - $this->addUpdateFormTags( - array( - 'id' => $newID, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + $this->addUpdateFormTags( + array( + 'id' => $newID, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); - } + } - - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $confirmedExtraMeta = array(); - - foreach ($extraMeta as $k => $v){ - - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); - - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_FORM,$newID,'extra_'.$cleanKey,$v); - - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; - - } - - } - - - - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT - if (!$silentInsert){ - - #} Add to automator - zeroBSCRM_FireInternalAutomator('form.new',array( - 'id'=>$newID, - 'data'=>$dataArr, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); - - } - - return $newID; - - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); - - #} Failed to Insert - return false; - - } - - } - - return false; - - } - - /** - * adds or updates a form's tags - * ... this is really just a wrapper for addUpdateObjectTags - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateFormTags($args=array()){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - - // generic pass-through (array of tag strings or tag IDs): - 'tag_input' => -1, - - // or either specific: - 'tagIDs' => -1, - 'tags' => -1, - - 'mode' => 'append' - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} ========== CHECK FIELDS ============ - - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; - - #} ========= / CHECK FIELDS =========== - - return $this->DAL()->addUpdateObjectTags( - array( - 'objtype' => ZBS_TYPE_FORM, - 'objid' => $id, - 'tag_input' => $tag_input, - 'tags' => $tags, - 'tagIDs' => $tagIDs, - 'mode' => $mode - ) - ); - - } - - - - /** - * deletes a form object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteForm($args=array()){ - - global $ZBSCRM_t,$wpdb,$zbs; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - 'saveOrphans' => true - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ - - // delete any tag links - $this->DAL()->deleteTagObjLinks(array( - - 'objtype' => ZBS_TYPE_FORM, - 'objid' => $id - )); - - // delete any external source information - $this->DAL()->delete_external_sources( array( - - 'obj_type' => ZBS_TYPE_FORM, - 'obj_id' => $id, - 'obj_source' => 'all', - - )); - } - - - $del = zeroBSCRM_db2_deleteGeneric($id,'forms'); - - #} Add to automator - zeroBSCRM_FireInternalAutomator('form.delete',array( - 'id'=>$id, - 'saveOrphans'=>$saveOrphans - )); - - return $del; - - } - - return false; - - } - - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array form (clean obj) - */ - private function tidy_form($obj=false,$withCustomFields=false){ - - $res = false; - - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = $obj->zbs_owner; - - - $res['title'] = $this->stripSlashes($obj->zbsf_title); - $res['style'] = $this->stripSlashes($obj->zbsf_style); - $res['views'] = (int)$obj->zbsf_views; - $res['conversions'] = (int)$obj->zbsf_conversions; - $res['label_header'] = $this->stripSlashes($obj->zbsf_label_header); - $res['label_subheader'] = $this->stripSlashes($obj->zbsf_label_subheader); - $res['label_firstname'] = $this->stripSlashes($obj->zbsf_label_firstname); - $res['label_lastname'] = $this->stripSlashes($obj->zbsf_label_lastname); - $res['label_email'] = $this->stripSlashes($obj->zbsf_label_email); - $res['label_message'] = $this->stripSlashes($obj->zbsf_label_message); - $res['label_button'] = $this->stripSlashes($obj->zbsf_label_button); - $res['label_successmsg'] = $this->stripSlashes($obj->zbsf_label_successmsg); - $res['label_spammsg'] = $this->stripSlashes($obj->zbsf_label_spammsg); - $res['include_terms_check'] = (bool)$obj->zbsf_include_terms_check; - $res['terms_url'] = $this->stripSlashes($obj->zbsf_terms_url); - $res['redir_url'] = $this->stripSlashes($obj->zbsf_redir_url); - $res['font'] = $this->stripSlashes($obj->zbsf_font); - $res['colour_bg'] = $this->stripSlashes($obj->zbsf_colour_bg); - $res['colour_font'] = $this->stripSlashes($obj->zbsf_colour_font); - $res['colour_emphasis'] = $this->stripSlashes($obj->zbsf_colour_emphasis); - $res['created'] = (int)$obj->zbsf_created; - //$res['created_date'] = (isset($obj->zbsf_created) && $obj->zbsf_created > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsf_created) : false; - $res['created_date'] = (isset($obj->zbsf_created) && $obj->zbsf_created > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsf_created,false,true) : false; - $res['lastupdated'] = (int)$obj->zbsf_lastupdated; - //$res['lastupdated_date'] = (isset($obj->zbsf_lastupdated) && $obj->zbsf_lastupdated > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsf_lastupdated) : false; - $res['lastupdated_date'] = (isset($obj->zbsf_lastupdated) && $obj->zbsf_lastupdated > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsf_lastupdated,false,true) : false; - - } - - return $res; - - } - - - /** - * Wrapper, use $this->getFormMeta($contactID,$key) for easy retrieval of singular form - * Simplifies $this->getMeta - * - * @param int objtype - * @param int objid - * @param string key - * - * @return array form meta result - */ - public function getFormMeta($id=-1,$key='',$default=false){ - - global $zbs; - - if (!empty($key)){ - - return $this->DAL()->getMeta(array( - - 'objtype' => ZBS_TYPE_FORM, - 'objid' => $id, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default, - 'ignoreowner' => true // for now !! - - )); - - } - - return $default; - } - - - - /** - * Returns an ownerid against a form - * - * @param int id form ID - * - * @return int form owner id - */ - public function getFormOwner($id=-1){ - - global $zbs; - - $id = (int)$id; - - if ($id > 0){ - - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_FORM, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); - - } - - return false; - - } - - - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * This does so based on the objectModel! - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - private function db_ready_form($obj=false){ - - // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); - - } - - - /** - * Takes full object and makes a "list view" boiled down version - * Used to generate listview objs - * - * @param array $obj (clean obj) - * - * @return array (listview ready obj) - */ - public function listViewObj($form=false,$columnsRequired=array()){ - - if (is_array($form) && isset($form['id'])){ - - $resArr = $form; - - // a lot of this is legacy format(zeroBSCRM_getDateFormat()); - - // use Proper field $resArr['added'] = $formatted_date; - - return $resArr; - - } - - return false; - - } + $confirmedExtraMeta = array(); - /** - * Increase the form views in +1 - * - * @param $form_id The form ID - * @return mixed Return the total views - */ - public function add_form_view( $form_id ) { - $form = $this->getForm( $form_id ); - $form[ 'views' ]++; + foreach ( $extraMeta as $k => $v ) { - $this->addUpdateForm( array( - 'id' => $form_id, - 'data' => $form, - ) ); - - return $form[ 'views' ]; - } - - /** - * Increase the form conversions in +1 - * - * @param $form_id The form ID - * @return mixed Return the total conversions - */ - public function add_form_conversion( $form_id ) { - $form = $this->getForm( $form_id ); - $form[ 'conversions' ]++; + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - $this->addUpdateForm( array( - 'id' => $form_id, - 'data' => $form, - ) ); - - return $form[ 'conversions' ]; - } - - // =========== / FORM ======================================================= - // =============================================================================== + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_FORM, $newID, 'extra_' . $cleanKey, $v ); + + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; + + } + } + + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // NEW CONTACT + if ( ! $silentInsert ) { + + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'form.new', + array( + 'id' => $newID, + 'data' => $dataArr, + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); + + } + + return $newID; + + } else { + + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); + + #} Failed to Insert + return false; + + } + } + + return false; + } + + /** + * adds or updates a form's tags + * ... this is really just a wrapper for addUpdateObjectTags + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateFormTags( $args = array() ) { + + global $ZBSCRM_t, $wpdb; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + + // generic pass-through (array of tag strings or tag IDs): + 'tag_input' => -1, + + // or either specific: + 'tagIDs' => -1, + 'tags' => -1, + + 'mode' => 'append', + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ + + #} ========== CHECK FIELDS ============ + + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } + + #} ========= / CHECK FIELDS =========== + + return $this->DAL()->addUpdateObjectTags( + array( + 'objtype' => ZBS_TYPE_FORM, + 'objid' => $id, + 'tag_input' => $tag_input, + 'tags' => $tags, + 'tagIDs' => $tagIDs, + 'mode' => $mode, + ) + ); + } + + /** + * deletes a form object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteForm( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'saveOrphans' => true, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ + + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + + // delete orphans? + if ( $saveOrphans === false ) { + + // delete any tag links + $this->DAL()->deleteTagObjLinks( + array( + + 'objtype' => ZBS_TYPE_FORM, + 'objid' => $id, + ) + ); + + // delete any external source information + $this->DAL()->delete_external_sources( + array( + + 'obj_type' => ZBS_TYPE_FORM, + 'obj_id' => $id, + 'obj_source' => 'all', + + ) + ); + } + + $del = zeroBSCRM_db2_deleteGeneric( $id, 'forms' ); + + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'form.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); + + return $del; + + } + + return false; + } + + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array form (clean obj) + */ + private function tidy_form( $obj = false, $withCustomFields = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = $obj->zbs_owner; + + $res['title'] = $this->stripSlashes( $obj->zbsf_title ); + $res['style'] = $this->stripSlashes( $obj->zbsf_style ); + $res['views'] = (int) $obj->zbsf_views; + $res['conversions'] = (int) $obj->zbsf_conversions; + $res['label_header'] = $this->stripSlashes( $obj->zbsf_label_header ); + $res['label_subheader'] = $this->stripSlashes( $obj->zbsf_label_subheader ); + $res['label_firstname'] = $this->stripSlashes( $obj->zbsf_label_firstname ); + $res['label_lastname'] = $this->stripSlashes( $obj->zbsf_label_lastname ); + $res['label_email'] = $this->stripSlashes( $obj->zbsf_label_email ); + $res['label_message'] = $this->stripSlashes( $obj->zbsf_label_message ); + $res['label_button'] = $this->stripSlashes( $obj->zbsf_label_button ); + $res['label_successmsg'] = $this->stripSlashes( $obj->zbsf_label_successmsg ); + $res['label_spammsg'] = $this->stripSlashes( $obj->zbsf_label_spammsg ); + $res['include_terms_check'] = (bool) $obj->zbsf_include_terms_check; + $res['terms_url'] = $this->stripSlashes( $obj->zbsf_terms_url ); + $res['redir_url'] = $this->stripSlashes( $obj->zbsf_redir_url ); + $res['font'] = $this->stripSlashes( $obj->zbsf_font ); + $res['colour_bg'] = $this->stripSlashes( $obj->zbsf_colour_bg ); + $res['colour_font'] = $this->stripSlashes( $obj->zbsf_colour_font ); + $res['colour_emphasis'] = $this->stripSlashes( $obj->zbsf_colour_emphasis ); + $res['created'] = (int) $obj->zbsf_created; + // $res['created_date'] = (isset($obj->zbsf_created) && $obj->zbsf_created > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsf_created) : false; + $res['created_date'] = ( isset( $obj->zbsf_created ) && $obj->zbsf_created > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsf_created, false, true ) : false; + $res['lastupdated'] = (int) $obj->zbsf_lastupdated; + // $res['lastupdated_date'] = (isset($obj->zbsf_lastupdated) && $obj->zbsf_lastupdated > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsf_lastupdated) : false; + $res['lastupdated_date'] = ( isset( $obj->zbsf_lastupdated ) && $obj->zbsf_lastupdated > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsf_lastupdated, false, true ) : false; + + } + + return $res; + } + + /** + * Wrapper, use $this->getFormMeta($contactID,$key) for easy retrieval of singular form + * Simplifies $this->getMeta + * + * @param int objtype + * @param int objid + * @param string key + * + * @return array form meta result + */ + public function getFormMeta( $id = -1, $key = '', $default = false ) { + + global $zbs; + + if ( ! empty( $key ) ) { + + return $this->DAL()->getMeta( + array( + + 'objtype' => ZBS_TYPE_FORM, + 'objid' => $id, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, + 'ignoreowner' => true, // for now !! + + ) + ); + + } + + return $default; + } + + /** + * Returns an ownerid against a form + * + * @param int id form ID + * + * @return int form owner id + */ + public function getFormOwner( $id = -1 ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 ) { + + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_FORM, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); + + } + + return false; + } + + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * This does so based on the objectModel! + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + private function db_ready_form( $obj = false ) { + + // use the generic? (override here if necessary) + return $this->db_ready_obj( $obj ); + } + + /** + * Takes full object and makes a "list view" boiled down version + * Used to generate listview objs + * + * @param array $obj (clean obj) + * + * @return array (listview ready obj) + */ + public function listViewObj( $form = false, $columnsRequired = array() ) { + + if ( is_array( $form ) && isset( $form['id'] ) ) { + + $resArr = $form; + + // a lot of this is legacy format(zeroBSCRM_getDateFormat()); + + // use Proper field $resArr['added'] = $formatted_date; + + return $resArr; + + } + + return false; + } + + /** + * Increase the form views in +1 + * + * @param $form_id The form ID + * @return mixed Return the total views + */ + public function add_form_view( $form_id ) { + $form = $this->getForm( $form_id ); + ++$form['views']; + + $this->addUpdateForm( + array( + 'id' => $form_id, + 'data' => $form, + ) + ); + + return $form['views']; + } + + /** + * Increase the form conversions in +1 + * + * @param $form_id The form ID + * @return mixed Return the total conversions + */ + public function add_form_conversion( $form_id ) { + $form = $this->getForm( $form_id ); + ++$form['conversions']; + + $this->addUpdateForm( + array( + 'id' => $form_id, + 'data' => $form, + ) + ); + + return $form['conversions']; + } + + // =========== / FORM ======================================================= + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Invoices.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Invoices.php index b2f39d5dd326..b8587b485727 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Invoices.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Invoices.php @@ -1,5 +1,6 @@ -> Invoices -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Invoices + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_invoices extends zbsDAL_ObjectLayer { + protected $objectType = ZBS_TYPE_INVOICE; + protected $objectDBPrefix = 'zbsi_'; + protected $include_in_templating = true; + protected $objectModel = array( + + /* + NOTE: + $zbsCustomerInvoiceFields Removed as of v3.0, invoice builder is very custom, UI wise, + .. and as the model can deal with saving + custom fields WITHOUT the global, there's no need + (whereas other objects input views are directed by these globals, Invs is separate, way MS made it) - protected $objectType = ZBS_TYPE_INVOICE; - protected $objectDBPrefix = 'zbsi_'; - protected $include_in_templating = true; - protected $objectModel = array( + OLD hard-typed: + $zbsCustomerInvoiceFields = array( - /* + 'status' => array( + 'select', 'Status','',array( + 'Draft', 'Unpaid', 'Paid', 'Overdue', 'Deleted' + ), 'essential' => true + ), - NOTE: + # NOTE! 'no' should now be ignored, (deprecated), moved to separate meta 'zbsid' - $zbsCustomerInvoiceFields Removed as of v3.0, invoice builder is very custom, UI wise, - .. and as the model can deal with saving + custom fields WITHOUT the global, there's no need - (whereas other objects input views are directed by these globals, Invs is separate, way MS made it) + // NOTE WH: when I hit this with column manager, loads didn't need to be shown + // so plz leave ,'nocolumn'=>true in tact :) - OLD hard-typed: - - $zbsCustomerInvoiceFields = array( + //'name' => array('text','Quote title','e.g. Chimney Rebuild'), + 'no' => array('text',__('Invoice number',"zero-bs-crm"),'e.g. 123456', 'essential' => true), #} No is ignored by edit routines :) + 'val'=> array('hidden',__('Invoice value',"zero-bs-crm"),'e.g. 500.00', 'essential' => true), + 'date' => array('date',__('Invoice date',"zero-bs-crm"),'', 'essential' => true), + 'notes' => array('textarea',__('Notes',"zero-bs-crm"),'','nocolumn'=>true), + 'ref' => array('text', __('Reference number',"zero-bs-crm"), 'e.g. Ref-123'), + 'due' => array('text', __('Invoice due',"zero-bs-crm"), ''), + 'logo' => array('text', __('logo url',"zero-bs-crm"), 'e.g. URL','nocolumn'=>true), - 'status' => array( - 'select', 'Status','',array( - 'Draft', 'Unpaid', 'Paid', 'Overdue', 'Deleted' - ), 'essential' => true - ), + 'bill' => array('text',__('invoice to',"zero-bs-crm"), 'e.g. mike@epicplugins.com','nocolumn'=>true), + 'ccbill' => array('text',__('copy invoice to',"zero-bs-crm"), 'e.g. you@you.com','nocolumn'=>true), - # NOTE! 'no' should now be ignored, (deprecated), moved to separate meta 'zbsid' + ); - // NOTE WH: when I hit this with column manager, loads didn't need to be shown - // so plz leave ,'nocolumn'=>true in tact :) - - //'name' => array('text','Quote title','e.g. Chimney Rebuild'), - 'no' => array('text',__('Invoice number',"zero-bs-crm"),'e.g. 123456', 'essential' => true), #} No is ignored by edit routines :) - 'val'=> array('hidden',__('Invoice value',"zero-bs-crm"),'e.g. 500.00', 'essential' => true), - 'date' => array('date',__('Invoice date',"zero-bs-crm"),'', 'essential' => true), - 'notes' => array('textarea',__('Notes',"zero-bs-crm"),'','nocolumn'=>true), - 'ref' => array('text', __('Reference number',"zero-bs-crm"), 'e.g. Ref-123'), - 'due' => array('text', __('Invoice due',"zero-bs-crm"), ''), - 'logo' => array('text', __('logo url',"zero-bs-crm"), 'e.g. URL','nocolumn'=>true), - - 'bill' => array('text',__('invoice to',"zero-bs-crm"), 'e.g. mike@epicplugins.com','nocolumn'=>true), - 'ccbill' => array('text',__('copy invoice to',"zero-bs-crm"), 'e.g. you@you.com','nocolumn'=>true), - - ); - - */ - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'id_override' => array( - 'fieldname' => 'zbsi_id_override', - 'format' => 'str', - 'force_unique' => true, // must be unique. This is required and breaking if true - 'can_be_blank' => true, // can be blank (if not unique) - 'max_len' => 128 - ), - 'parent' => array('fieldname' => 'zbsi_parent', 'format' => 'int'), - 'status' => array( - 'fieldname' => 'zbsi_status', - 'format' => 'str', - 'max_len' => 50 - ), - 'hash' => array('fieldname' => 'zbsi_hash', 'format' => 'str'), - 'pdf_template' => array('fieldname' => 'zbsi_pdf_template', 'format' => 'str'), - 'portal_template' => array('fieldname' => 'zbsi_portal_template', 'format' => 'str'), - 'email_template' => array('fieldname' => 'zbsi_email_template', 'format' => 'str'), - 'invoice_frequency' => array('fieldname' => 'zbsi_invoice_frequency', 'format' => 'int'), - 'currency' => array('fieldname' => 'zbsi_currency', 'format' => 'curr'), - 'pay_via' => array('fieldname' => 'zbsi_pay_via', 'format' => 'int'), - /* -1 = bacs/can'tpay online - 0 = default/no setting - 1 = paypal - 2 = stripe - 3 = worldpay - */ - 'logo_url' => array( - 'fieldname' => 'zbsi_logo_url', - 'format' => 'str', - 'max_len' => 300 - ), - 'address_to_objtype' => array('fieldname' => 'zbsi_address_to_objtype', 'format' => 'int'), - 'addressed_from' => array( - 'fieldname' => 'zbsi_addressed_from', - 'format' => 'str', - 'max_len' => 600 - ), - 'addressed_to' => array( - 'fieldname' => 'zbsi_addressed_to', - 'format' => 'str', - 'max_len' => 600 - ), - 'allow_partial' => array('fieldname' => 'zbsi_allow_partial', 'format' => 'bool'), - 'allow_tip' => array('fieldname' => 'zbsi_allow_tip', 'format' => 'bool'), - 'send_attachments' => array('fieldname' => 'zbsi_send_attachments', 'format' => 'bool'), // note, from 4.0.9 we removed this from the front-end ui as we now show a modal option pre-send allowing user to chose which pdf's to attach - 'hours_or_quantity' => array('fieldname' => 'zbsi_hours_or_quantity', 'format' => 'bool'), - 'date' => array('fieldname' => 'zbsi_date', 'format' => 'uts'), - 'due_date' => array('fieldname' => 'zbsi_due_date', 'format' => 'uts'), - 'paid_date' => array('fieldname' => 'zbsi_paid_date', 'format' => 'uts'), - 'hash_viewed' => array('fieldname' => 'zbsi_hash_viewed', 'format' => 'uts'), - 'hash_viewed_count' => array('fieldname' => 'zbsi_hash_viewed_count', 'format' => 'int'), - 'portal_viewed' => array('fieldname' => 'zbsi_portal_viewed', 'format' => 'uts'), - 'portal_viewed_count' => array('fieldname' => 'zbsi_portal_viewed_count', 'format' => 'int'), - 'net' => array('fieldname' => 'zbsi_net', 'format' => 'decimal'), - 'discount' => array('fieldname' => 'zbsi_discount', 'format' => 'decimal'), - 'discount_type' => array('fieldname' => 'zbsi_discount_type', 'format' => 'str'), - 'shipping' => array('fieldname' => 'zbsi_shipping', 'format' => 'decimal'), - 'shipping_taxes' => array('fieldname' => 'zbsi_shipping_taxes', 'format' => 'str'), - 'shipping_tax' => array('fieldname' => 'zbsi_shipping_tax', 'format' => 'decimal'), - 'taxes' => array('fieldname' => 'zbsi_taxes', 'format' => 'str'), - 'tax' => array('fieldname' => 'zbsi_tax', 'format' => 'decimal'), - 'total' => array('fieldname' => 'zbsi_total', 'format' => 'decimal'), - 'created' => array('fieldname' => 'zbsi_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsi_lastupdated', 'format' => 'uts'), - - ); - - - // hardtyped list of types this object type is commonly linked to - protected $linkedToObjectTypes = array( - - ZBS_TYPE_CONTACT, - ZBS_TYPE_COMPANY - - ); + */ + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'id_override' => array( + 'fieldname' => 'zbsi_id_override', + 'format' => 'str', + 'force_unique' => true, // must be unique. This is required and breaking if true + 'can_be_blank' => true, // can be blank (if not unique) + 'max_len' => 128, + ), + 'parent' => array( + 'fieldname' => 'zbsi_parent', + 'format' => 'int', + ), + 'status' => array( + 'fieldname' => 'zbsi_status', + 'format' => 'str', + 'max_len' => 50, + ), + 'hash' => array( + 'fieldname' => 'zbsi_hash', + 'format' => 'str', + ), + 'pdf_template' => array( + 'fieldname' => 'zbsi_pdf_template', + 'format' => 'str', + ), + 'portal_template' => array( + 'fieldname' => 'zbsi_portal_template', + 'format' => 'str', + ), + 'email_template' => array( + 'fieldname' => 'zbsi_email_template', + 'format' => 'str', + ), + 'invoice_frequency' => array( + 'fieldname' => 'zbsi_invoice_frequency', + 'format' => 'int', + ), + 'currency' => array( + 'fieldname' => 'zbsi_currency', + 'format' => 'curr', + ), + 'pay_via' => array( + 'fieldname' => 'zbsi_pay_via', + 'format' => 'int', + ), + /* + -1 = bacs/can'tpay online + 0 = default/no setting + 1 = paypal + 2 = stripe + 3 = worldpay + */ + 'logo_url' => array( + 'fieldname' => 'zbsi_logo_url', + 'format' => 'str', + 'max_len' => 300, + ), + 'address_to_objtype' => array( + 'fieldname' => 'zbsi_address_to_objtype', + 'format' => 'int', + ), + 'addressed_from' => array( + 'fieldname' => 'zbsi_addressed_from', + 'format' => 'str', + 'max_len' => 600, + ), + 'addressed_to' => array( + 'fieldname' => 'zbsi_addressed_to', + 'format' => 'str', + 'max_len' => 600, + ), + 'allow_partial' => array( + 'fieldname' => 'zbsi_allow_partial', + 'format' => 'bool', + ), + 'allow_tip' => array( + 'fieldname' => 'zbsi_allow_tip', + 'format' => 'bool', + ), + 'send_attachments' => array( + 'fieldname' => 'zbsi_send_attachments', + 'format' => 'bool', + ), // note, from 4.0.9 we removed this from the front-end ui as we now show a modal option pre-send allowing user to chose which pdf's to attach + 'hours_or_quantity' => array( + 'fieldname' => 'zbsi_hours_or_quantity', + 'format' => 'bool', + ), + 'date' => array( + 'fieldname' => 'zbsi_date', + 'format' => 'uts', + ), + 'due_date' => array( + 'fieldname' => 'zbsi_due_date', + 'format' => 'uts', + ), + 'paid_date' => array( + 'fieldname' => 'zbsi_paid_date', + 'format' => 'uts', + ), + 'hash_viewed' => array( + 'fieldname' => 'zbsi_hash_viewed', + 'format' => 'uts', + ), + 'hash_viewed_count' => array( + 'fieldname' => 'zbsi_hash_viewed_count', + 'format' => 'int', + ), + 'portal_viewed' => array( + 'fieldname' => 'zbsi_portal_viewed', + 'format' => 'uts', + ), + 'portal_viewed_count' => array( + 'fieldname' => 'zbsi_portal_viewed_count', + 'format' => 'int', + ), + 'net' => array( + 'fieldname' => 'zbsi_net', + 'format' => 'decimal', + ), + 'discount' => array( + 'fieldname' => 'zbsi_discount', + 'format' => 'decimal', + ), + 'discount_type' => array( + 'fieldname' => 'zbsi_discount_type', + 'format' => 'str', + ), + 'shipping' => array( + 'fieldname' => 'zbsi_shipping', + 'format' => 'decimal', + ), + 'shipping_taxes' => array( + 'fieldname' => 'zbsi_shipping_taxes', + 'format' => 'str', + ), + 'shipping_tax' => array( + 'fieldname' => 'zbsi_shipping_tax', + 'format' => 'decimal', + ), + 'taxes' => array( + 'fieldname' => 'zbsi_taxes', + 'format' => 'str', + ), + 'tax' => array( + 'fieldname' => 'zbsi_tax', + 'format' => 'decimal', + ), + 'total' => array( + 'fieldname' => 'zbsi_total', + 'format' => 'decimal', + ), + 'created' => array( + 'fieldname' => 'zbsi_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsi_lastupdated', + 'format' => 'uts', + ), + + ); + + // hardtyped list of types this object type is commonly linked to + protected $linkedToObjectTypes = array( + + ZBS_TYPE_CONTACT, + ZBS_TYPE_COMPANY, + + ); /** * Events_Manager instance. Manages CRM events. @@ -164,21 +266,34 @@ class zbsDAL_invoices extends zbsDAL_ObjectLayer { */ private $events_manager; - function __construct($args=array()) { + function __construct( $args = array() ) { + #} =========== LOAD ARGS ============== + $defaultArgs = array( - #} =========== LOAD ARGS ============== - $defaultArgs = array( + // 'tag' => false, - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= $this->events_manager = new Events_Manager(); add_filter( 'jpcrm_listview_filters', array( $this, 'add_listview_filters' ) ); - } + } /** * Adds items to listview filter using `jpcrm_listview_filters` hook. @@ -203,582 +318,661 @@ public function add_listview_filters( $listview_filters ) { return $listview_filters; } - // =============================================================================== - // =========== INVOICE ======================================================= - - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ - - return $this->getInvoice($ID); - - } - - // generic get (by ID list) - // Super simplistic wrapper used by MVP Export v3.0 - public function getIDList($IDs=false){ - - return $this->getInvoices(array( - 'inArr' => $IDs, - 'withOwner' => true, - 'withAssigned' => true, - 'page' => -1, - 'perPage' => -1 - )); - - } - - // generic get (EVERYTHING) - // expect heavy load! - public function getAll($IDs=false){ - - return $this->getInvoices(array( - 'withOwner' => true, - 'withAssigned' => true, - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => -1, - 'perPage' => -1, - )); - - } - - // generic get count of (EVERYTHING) - public function getFullCount(){ - - return $this->getInvoices(array( - 'count' => true, - 'page' => -1, - 'perPage' => -1, - )); - - } - - /** - * returns full invoice line +- details - * - * @param int id invoice id - * @param array $args Associative array of arguments - * - * @return array invoice object - */ - public function getInvoice($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - // if theset wo passed, will search based on these - 'idOverride' => false, // directly checks 1:1 match id_override - 'externalSource' => false, - 'externalSourceUID' => false, - 'hash' => false, - - // with what? - 'withLineItems' => true, - 'withCustomFields' => true, - 'withTransactions' => false, // gets trans associated with inv as well - 'withAssigned' => false, // return ['contact'] & ['company'] objs if has link - 'withTags' => false, - 'withOwner' => false, - 'withFiles' => false, - 'withTotals' => false, // uses $this->generateTotalsTable to also calc discount + taxes on fly - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE), // this'll let you not-check the owner of obj - - // returns scalar ID of line - 'onlyID' => false, - - 'fields' => false // false = *, array = fieldnames - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check ID - $id = (int)$id; - if ( - (!empty($id) && $id > 0) - || - (!empty($email)) - || - (!empty($hash)) - || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ - - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; - - - #} ============= PRE-QUERY ============ - - #} Custom Fields - if ($withCustomFields && !$onlyID){ - - #} Retrieve any cf - $custFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_INVOICE)); - - #} Cycle through + build into query - if (is_array($custFields)) foreach ($custFields as $cK => $cF){ - - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = invoice.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '".$cK."'"; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_INVOICE; - - } - - } - - $selector = 'invoice.*'; - if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $selector = ''; + // =============================================================================== + // =========== INVOICE ======================================================= - // always needs id, so add if not present - if (!in_array('ID',$fields)) $selector = 'invoice.ID'; + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'invoice.'.$f; - } - } else if ($onlyID){ - $selector = 'invoice.ID'; - } + return $this->getInvoice( $ID ); + } + + // generic get (by ID list) + // Super simplistic wrapper used by MVP Export v3.0 + public function getIDList( $IDs = false ) { + + return $this->getInvoices( + array( + 'inArr' => $IDs, + 'withOwner' => true, + 'withAssigned' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } - #} ============ / PRE-QUERY =========== + // generic get (EVERYTHING) + // expect heavy load! + public function getAll( $IDs = false ) { + + return $this->getInvoices( + array( + 'withOwner' => true, + 'withAssigned' => true, + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + // generic get count of (EVERYTHING) + public function getFullCount() { + return $this->getInvoices( + array( + 'count' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['invoices'].' as invoice'; - #} ============= WHERE ================ + /** + * returns full invoice line +- details + * + * @param int id invoice id + * @param array $args Associative array of arguments + * + * @return array invoice object + */ + public function getInvoice( $id = -1, $args = array() ) { - if (!empty($id) && $id > 0){ + global $zbs; - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // if theset wo passed, will search based on these + 'idOverride' => false, // directly checks 1:1 match id_override + 'externalSource' => false, + 'externalSourceUID' => false, + 'hash' => false, + + // with what? + 'withLineItems' => true, + 'withCustomFields' => true, + 'withTransactions' => false, // gets trans associated with inv as well + 'withAssigned' => false, // return ['contact'] & ['company'] objs if has link + 'withTags' => false, + 'withOwner' => false, + 'withFiles' => false, + 'withTotals' => false, // uses $this->generateTotalsTable to also calc discount + taxes on fly + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + 'fields' => false, // false = *, array = fieldnames + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + #} Check ID + $id = (int) $id; + if ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $email ) ) + || + ( ! empty( $hash ) ) + || + ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) + ) { + + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $extraSelect = ''; + + #} ============= PRE-QUERY ============ + + #} Custom Fields + if ( $withCustomFields && ! $onlyID ) { + + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_INVOICE ) ); + + #} Cycle through + build into query + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { + + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . " WHERE zbscf_objid = invoice.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '" . $cK . "'"; + + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_INVOICE; - } - - if (!empty($idOverride) && $idOverride > 0){ + } + } + } - #} Add idOverride - $wheres['idOverride'] = array('zbsi_id_override','=','%d',$idOverride); + $selector = 'invoice.*'; + if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $selector = ''; - } + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'invoice.ID'; + } - /* 3.0.13 WH removed - individual getInvoice should not have searchPhrase. - #} Add Search phrase - if (!empty($searchPhrase)){ + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'invoice.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'invoice.ID'; + } - // search? - ALL THESE COLS should probs have index of FULLTEXT in db? - $searchWheres = array(); - $searchWheres['search_ref'] = array('zbsi_id_override','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_total'] = array('zbsi_total','LIKE','%s',$searchPhrase.'%'); + #} ============ / PRE-QUERY =========== - // 3.0.13 - Added ability to search custom fields (optionally) - $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); - if ($customFieldSearch == 1){ - - // simplistic add - // NOTE: This IGNORES ownership of custom field lines. - $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE zbscf_objval LIKE %s AND zbscf_objtype = ".ZBS_TYPE_INVOICE.")",'%'.$searchPhrase.'%'); + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['invoices'] . ' as invoice'; + #} ============= WHERE ================ - } + if ( ! empty( $id ) && $id > 0 ) { - // This generates a query like 'zbsf_fname LIKE %s OR zbsf_lname LIKE %s', - // which we then need to include as direct subquery (below) in main query :) - $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - - if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + } - } + if ( ! empty( $idOverride ) && $idOverride > 0 ) { - } */ - - if (!empty($hash)){ + #} Add idOverride + $wheres['idOverride'] = array( 'zbsi_id_override', '=', '%d', $idOverride ); - #} Add hash - $wheres['hash'] = array('zbsi_hash','=','%s',$hash); + } - } - - if (!empty($externalSource) && !empty($externalSourceUID)){ + /* + 3.0.13 WH removed - individual getInvoice should not have searchPhrase. + #} Add Search phrase + if (!empty($searchPhrase)){ - $wheres['extsourcecheck'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_INVOICE." AND zbss_source = %s AND zbss_uid = %s)",array($externalSource,$externalSourceUID)); + // search? - ALL THESE COLS should probs have index of FULLTEXT in db? + $searchWheres = array(); + $searchWheres['search_ref'] = array('zbsi_id_override','LIKE','%s','%'.$searchPhrase.'%'); + $searchWheres['search_total'] = array('zbsi_total','LIKE','%s',$searchPhrase.'%'); - } + // 3.0.13 - Added ability to search custom fields (optionally) + $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); + if ($customFieldSearch == 1){ - #} ============ / WHERE ============== + // simplistic add + // NOTE: This IGNORES ownership of custom field lines. + $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE zbscf_objval LIKE %s AND zbscf_objtype = ".ZBS_TYPE_INVOICE.")",'%'.$searchPhrase.'%'); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + } - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + // This generates a query like 'zbsf_fname LIKE %s OR zbsf_lname LIKE %s', + // which we then need to include as direct subquery (below) in main query :) + $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ - try { + // add it + $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + } - } catch (Exception $e){ + } */ - #} General SQL Err - $this->catchSQLError($e); + if ( ! empty( $hash ) ) { - } + #} Add hash + $wheres['hash'] = array( 'zbsi_hash', '=', '%s', $hash ); - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + } - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID) return $potentialRes->ID; - - // tidy - if (is_array($fields)){ - // guesses fields based on table col names - $res = $this->lazyTidyGeneric($potentialRes); - } else { - // proper tidy - $res = $this->tidy_invoice($potentialRes,$withCustomFields); - } + if ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) { - if ($withLineItems){ + $wheres['extsourcecheck'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_INVOICE . ' AND zbss_source = %s AND zbss_uid = %s)', array( $externalSource, $externalSourceUID ) ); - // add all line item lines - $res['lineitems'] = $this->DAL()->lineitems->getLineitems(array('associatedObjType'=>ZBS_TYPE_INVOICE,'associatedObjID'=>$potentialRes->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LINEITEM))); - - } + } - if ($withTransactions){ + #} ============ / WHERE ============== - // add all transaction item lines - $res['transactions'] = $this->DAL()->transactions->getTransactions(array('assignedInvoice'=>$potentialRes->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION))); - - } + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - if ($withAssigned){ + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - /* This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - // add all assigned contacts/companies - $res['contacts'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + try { - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - .. but we use 1:1, at least now: */ + } catch ( Exception $e ) { - // add all assigned contacts/companies - $res['contact'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$potentialRes->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + #} General SQL Err + $this->catchSQLError( $e ); - $res['company'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$potentialRes->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + } - - } + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - if ($withTags){ + #} Has results, tidy + return - // add all tags lines - $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_INVOICE,'objid'=>$potentialRes->ID)); - - } - - if ($withFiles){ - - $res['files'] = zeroBSCRM_files_getFiles('invoice',$potentialRes->ID); - - } + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } - if ($withTotals){ + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_invoice( $potentialRes, $withCustomFields ); + } - // add all tags lines - $res['totals'] = $this->generateTotalsTable($res); + if ( $withLineItems ) { - } + // add all line item lines + $res['lineitems'] = $this->DAL()->lineitems->getLineitems( + array( + 'associatedObjType' => ZBS_TYPE_INVOICE, + 'associatedObjID' => $potentialRes->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LINEITEM ), + ) + ); - return $res; + } - } + if ( $withTransactions ) { - } // / if ID + // add all transaction item lines + $res['transactions'] = $this->DAL()->transactions->getTransactions( + array( + 'assignedInvoice' => $potentialRes->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), + ) + ); - return false; + } - } + if ( $withAssigned ) { + + /* + This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + + // add all assigned contacts/companies + $res['contacts'] = $this->DAL()->contacts->getContacts(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + + $res['companies'] = $this->DAL()->companies->getCompanies(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + + .. but we use 1:1, at least now: */ + + // add all assigned contacts/companies + $res['contact'] = $this->DAL()->contacts->getContacts( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo' => $potentialRes->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); + + $res['company'] = $this->DAL()->companies->getCompanies( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo' => $potentialRes->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); - /** - * returns invoice detail lines - * - * @param array $args Associative array of arguments - * - * @return array of invoice lines - */ - public function getInvoices($args=array()){ + } - global $zbs; + if ( $withTags ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_INVOICE, + 'objid' => $potentialRes->ID, + ) + ); - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches id_override (ref) (not lineitems yet) - 'inArr' => false, - 'isTagged' => false, // 1x INT OR array(1,2,3) - 'isNotTagged' => false, // 1x INT OR array(1,2,3) - 'ownedBy' => false, - 'externalSource' => false, // e.g. paypal - 'olderThan' => false, // uts - 'newerThan' => false, // uts - 'hasStatus' => false, // Lead (this takes over from the quick filter post 19/6/18) - 'otherStatus' => false, // status other than 'Lead' - 'assignedContact' => false, // assigned to contact id (int) - 'assignedCompany' => false, // assigned to company id (int) - 'quickFilters' => false, // booo + } - // returns - 'count' => false, - 'withLineItems' => true, - 'withCustomFields' => true, - 'withTransactions' => false, // gets trans associated with inv as well - 'withTags' => false, - 'withOwner' => false, - 'withAssigned' => false, // return ['contact'] & ['company'] objs if has link - 'withFiles' => false, - 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) - 'withTotals' => false, // uses $this->generateTotalsTable to also calc discount + taxes on fly + if ( $withFiles ) { - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 100, - 'whereCase' => 'AND', // DEFAULT = AND + $res['files'] = zeroBSCRM_files_getFiles( 'invoice', $potentialRes->ID ); - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE), // this'll let you not-check the owner of obj + } + if ( $withTotals ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + // add all tags lines + $res['totals'] = $this->generateTotalsTable( $res ); - global $ZBSCRM_t,$wpdb,$zbs; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; + } - #} ============= PRE-QUERY ============ + return $res; - #} Capitalise this - $sortOrder = strtoupper($sortOrder); + } + } // / if ID - #} If just count, turn off any extra gumpf - if ($count) { - $withCustomFields = false; - $withTags = false; - $withTransactions = false; - $withOwner = false; - $withAssigned = false; - } + return false; + } - #} If onlyColumns, validate - if ($onlyColumns){ + /** + * returns invoice detail lines + * + * @param array $args Associative array of arguments + * + * @return array of invoice lines + */ + public function getInvoices( $args = array() ) { - #} onlyColumns build out a field arr - if (is_array($onlyColumns) && count($onlyColumns) > 0){ + global $zbs; - $onlyColumnsFieldArr = array(); - foreach ($onlyColumns as $col){ + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => '', // searches id_override (ref) (not lineitems yet) + 'inArr' => false, + 'isTagged' => false, // 1x INT OR array(1,2,3) + 'isNotTagged' => false, // 1x INT OR array(1,2,3) + 'ownedBy' => false, + 'externalSource' => false, // e.g. paypal + 'olderThan' => false, // uts + 'newerThan' => false, // uts + 'hasStatus' => false, // Lead (this takes over from the quick filter post 19/6/18) + 'otherStatus' => false, // status other than 'Lead' + 'assignedContact' => false, // assigned to contact id (int) + 'assignedCompany' => false, // assigned to company id (int) + 'quickFilters' => false, // booo + + // returns + 'count' => false, + 'withLineItems' => true, + 'withCustomFields' => true, + 'withTransactions' => false, // gets trans associated with inv as well + 'withTags' => false, + 'withOwner' => false, + 'withAssigned' => false, // return ['contact'] & ['company'] objs if has link + 'withFiles' => false, + 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) + 'withTotals' => false, // uses $this->generateTotalsTable to also calc discount + taxes on fly + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 100, + 'whereCase' => 'AND', // DEFAULT = AND + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + global $ZBSCRM_t, $wpdb, $zbs; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; + + #} ============= PRE-QUERY ============ + + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); + + #} If just count, turn off any extra gumpf + if ( $count ) { + $withCustomFields = false; + $withTags = false; + $withTransactions = false; + $withOwner = false; + $withAssigned = false; + } - // find db col key from field key (e.g. fname => zbsc_fname) - $dbCol = ''; if (isset($this->objectModel[$col]) && isset($this->objectModel[$col]['fieldname'])) $dbCol = $this->objectModel[$col]['fieldname']; + #} If onlyColumns, validate + if ( $onlyColumns ) { - if (!empty($dbCol)){ + #} onlyColumns build out a field arr + if ( is_array( $onlyColumns ) && count( $onlyColumns ) > 0 ) { - $onlyColumnsFieldArr[$dbCol] = $col; + $onlyColumnsFieldArr = array(); + foreach ( $onlyColumns as $col ) { - } + // find db col key from field key (e.g. fname => zbsc_fname) + $dbCol = ''; + if ( isset( $this->objectModel[ $col ] ) && isset( $this->objectModel[ $col ]['fieldname'] ) ) { + $dbCol = $this->objectModel[ $col ]['fieldname']; + } - } + if ( ! empty( $dbCol ) ) { - } + $onlyColumnsFieldArr[ $dbCol ] = $col; - // if legit cols: - if (isset($onlyColumnsFieldArr) && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + } + } + } - $onlyColumns = true; - - // If onlyColumns, turn off extras - $withCustomFields = false; - $withTags = false; - $withTransactions = false; - $withOwner = false; - $withAssigned = false; - $withTotals = false; + // if legit cols: + if ( isset( $onlyColumnsFieldArr ) && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - } else { + $onlyColumns = true; - // deny - $onlyColumns = false; + // If onlyColumns, turn off extras + $withCustomFields = false; + $withTags = false; + $withTransactions = false; + $withOwner = false; + $withAssigned = false; + $withTotals = false; - } + } else { + // deny + $onlyColumns = false; - } + } + } - #} Custom Fields + #} Custom Fields // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. - if ($withCustomFields){ - - #} Retrieve any cf - $custFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_INVOICE)); + if ( $withCustomFields ) { + + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_INVOICE ) ); + + #} Cycle through + build into query + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { + + // custom field (e.g. 'third name') it'll be passed here as 'third-name' + // ... problem is mysql does not like that :) so we have to chage here: + // in this case we prepend cf's with cf_ and we switch - for _ + $cKey = 'cf_' . str_replace( '-', '_', $cK ); - #} Cycle through + build into query - if (is_array($custFields)) foreach ($custFields as $cK => $cF){ + // we also check the $sortByField in case that's the same cf + if ( $cK == $sortByField ) { - // custom field (e.g. 'third name') it'll be passed here as 'third-name' - // ... problem is mysql does not like that :) so we have to chage here: - // in this case we prepend cf's with cf_ and we switch - for _ - $cKey = 'cf_'.str_replace('-','_',$cK); + // sort by + $sortByField = $cKey; - // we also check the $sortByField in case that's the same cf - if ($cK == $sortByField){ + // check if sort needs any CAST (e.g. numeric): + $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); - // sort by - $sortByField = $cKey; + } - // check if sort needs any CAST (e.g. numeric): - $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = invoice.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ' . $cKey; - } + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_INVOICE; - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = invoice.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ".$cKey; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_INVOICE; + } + } + } - } + #} ============ / PRE-QUERY =========== - } + #} Build query + $query = 'SELECT invoice.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['invoices'] . ' as invoice' . $joinQ; - #} ============ / PRE-QUERY =========== + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(invoice.ID) FROM ' . $ZBSCRM_t['invoices'] . ' as invoice' . $joinQ; + } - #} Build query - $query = "SELECT invoice.*".$extraSelect." FROM ".$ZBSCRM_t['invoices'].' as invoice'.$joinQ; + #} onlyColumns override + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - #} Count override - if ($count) $query = "SELECT COUNT(invoice.ID) FROM ".$ZBSCRM_t['invoices'].' as invoice'.$joinQ; + $columnStr = ''; + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - #} onlyColumns override - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + if ( ! empty( $columnStr ) ) { + $columnStr .= ','; + } + // this presumes str is db-safe? could do with sanitation? + $columnStr .= $colDBKey; - $columnStr = ''; - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + } - if (!empty($columnStr)) $columnStr .= ','; - // this presumes str is db-safe? could do with sanitation? - $columnStr .= $colDBKey; + $query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['invoices'] . ' as invoice' . $joinQ; - } + } - $query = "SELECT ".$columnStr." FROM ".$ZBSCRM_t['invoices'].' as invoice'.$joinQ; + #} ============= WHERE ================ - } + #} Add Search phrase + if ( ! empty( $searchPhrase ) ) { - #} ============= WHERE ================ + // search? - ALL THESE COLS should probs have index of FULLTEXT in db? + $searchWheres = array(); + $searchWheres['search_ID'] = array( 'ID', '=', '%d', $searchPhrase ); + $searchWheres['search_ref'] = array( 'zbsi_id_override', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_total'] = array( 'zbsi_total', 'LIKE', '%s', $searchPhrase . '%' ); - #} Add Search phrase - if (!empty($searchPhrase)){ + // 3.0.13 - Added ability to search custom fields (optionally) + $customFieldSearch = zeroBSCRM_getSetting( 'customfieldsearch' ); + if ( $customFieldSearch == 1 ) { - // search? - ALL THESE COLS should probs have index of FULLTEXT in db? - $searchWheres = array(); - $searchWheres['search_ID'] = array('ID','=','%d',$searchPhrase); - $searchWheres['search_ref'] = array('zbsi_id_override','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_total'] = array('zbsi_total','LIKE','%s',$searchPhrase.'%'); + // simplistic add + // NOTE: This IGNORES ownership of custom field lines. + $searchWheres['search_customfields'] = array( 'ID', 'IN', '(SELECT zbscf_objid FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objval LIKE %s AND zbscf_objtype = ' . ZBS_TYPE_INVOICE . ')', '%' . $searchPhrase . '%' ); - // 3.0.13 - Added ability to search custom fields (optionally) - $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); - if ($customFieldSearch == 1){ - - // simplistic add - // NOTE: This IGNORES ownership of custom field lines. - $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE zbscf_objval LIKE %s AND zbscf_objtype = ".ZBS_TYPE_INVOICE.")",'%'.$searchPhrase.'%'); + } - } + // This generates a query like 'zbsi_fname LIKE %s OR zbsi_lname LIKE %s', + // which we then need to include as direct subquery (below) in main query :) + $searchQueryArr = $this->buildWheres( $searchWheres, '', array(), 'OR', false ); - // This generates a query like 'zbsi_fname LIKE %s OR zbsi_lname LIKE %s', - // which we then need to include as direct subquery (below) in main query :) - $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - - if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ + if ( is_array( $searchQueryArr ) && isset( $searchQueryArr['where'] ) && ! empty( $searchQueryArr['where'] ) ) { - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + // add it + $wheres['direct'][] = array( '(' . $searchQueryArr['where'] . ')', $searchQueryArr['params'] ); - } + } + } - } + #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { - #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) - if (is_array($inArr) && count($inArr) > 0){ + // clean for ints + $inArrChecked = array(); + foreach ( $inArr as $x ) { + $inArrChecked[] = (int) $x; } - // clean for ints - $inArrChecked = array(); foreach ($inArr as $x){ $inArrChecked[] = (int)$x; } + // add where + $wheres['inarray'] = array( 'ID', 'IN', '(' . implode( ',', $inArrChecked ) . ')' ); - // add where - $wheres['inarray'] = array('ID','IN','('.implode(',',$inArrChecked).')'); + } - } + #} Owned by + if ( ! empty( $ownedBy ) && $ownedBy > 0 ) { - #} Owned by - if (!empty($ownedBy) && $ownedBy > 0){ - - // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) - // but this is only here until MIGRATED to db2 globally - //$wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); - // Use obj links now - $wheres['ownedBy'] = array('zbs_owner','=','%s',$ownedBy); + // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) + // but this is only here until MIGRATED to db2 globally + // $wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); + // Use obj links now + $wheres['ownedBy'] = array( 'zbs_owner', '=', '%s', $ownedBy ); - } + } - // External sources - if ( !empty( $externalSource ) ){ + // External sources + if ( ! empty( $externalSource ) ) { - // NO owernship built into this, check when roll out multi-layered ownsership - $wheres['externalsource'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_INVOICE." AND zbss_source = %s)",$externalSource); + // NO owernship built into this, check when roll out multi-layered ownsership + $wheres['externalsource'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_INVOICE . ' AND zbss_source = %s)', $externalSource ); - } + } // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed // quick addition for mike @@ -797,14 +991,14 @@ public function getInvoices($args=array()){ // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed - #} Quick filters - adapted from DAL1 (probs can be slicker) - if (is_array($quickFilters) && count($quickFilters) > 0){ + #} Quick filters - adapted from DAL1 (probs can be slicker) + if ( is_array( $quickFilters ) && count( $quickFilters ) > 0 ) { - // cycle through - foreach ($quickFilters as $qFilter){ + // cycle through + foreach ( $quickFilters as $qFilter ) { - // where status = x - // USE hasStatus above now... + // where status = x + // USE hasStatus above now... if ( str_starts_with( $qFilter, 'status_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $quick_filter_status = substr( $qFilter, 7 ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -812,1406 +1006,1565 @@ public function getInvoices($args=array()){ } else { - // if we've hit no filter query, let external logic hook in to provide alternatives - // First used in WooSync module - $wheres = apply_filters( 'jpcrm_invoice_query_quickfilter', $wheres, $qFilter ); + // if we've hit no filter query, let external logic hook in to provide alternatives + // First used in WooSync module + $wheres = apply_filters( 'jpcrm_invoice_query_quickfilter', $wheres, $qFilter ); } - } - } // / quickfilters + } + } // / quickfilters - #} Is Tagged (expects 1 tag ID OR array) + #} Is Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isTagged) && count($isTagged) == 1) $isTagged = $isTagged[0]; + // catch 1 item arr + if ( is_array( $isTagged ) && count( $isTagged ) == 1 ) { + $isTagged = $isTagged[0]; + } if ( ! empty( $isTagged ) && ! is_array( $isTagged ) && $isTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = invoice.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_INVOICE,$isTagged)); + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = invoice.ID AND zbstl_tagid = %d) > 0)', array( ZBS_TYPE_INVOICE, $isTagged ) ); - } else if (is_array($isTagged) && count($isTagged) > 0){ + } elseif ( is_array( $isTagged ) && count( $isTagged ) > 0 ) { - // foreach in array :) - $tagStr = ''; - foreach ($isTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + // foreach in array :) + $tagStr = ''; + foreach ( $isTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = invoice.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_INVOICE,$tagStr)); + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = invoice.ID AND zbstl_tagid IN (%s)) > 0)', array( ZBS_TYPE_INVOICE, $tagStr ) ); - } - #} Is NOT Tagged (expects 1 tag ID OR array) + } + } + #} Is NOT Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isNotTagged) && count($isNotTagged) == 1) $isNotTagged = $isNotTagged[0]; + // catch 1 item arr + if ( is_array( $isNotTagged ) && count( $isNotTagged ) == 1 ) { + $isNotTagged = $isNotTagged[0]; + } - if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = invoice.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_INVOICE,$isNotTagged)); + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = invoice.ID AND zbstl_tagid = %d) = 0)', array( ZBS_TYPE_INVOICE, $isNotTagged ) ); - } else if (is_array($isNotTagged) && count($isNotTagged) > 0){ + } elseif ( is_array( $isNotTagged ) && count( $isNotTagged ) > 0 ) { - // foreach in array :) - $tagStr = ''; - foreach ($isNotTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + // foreach in array :) + $tagStr = ''; + foreach ( $isNotTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = invoice.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_INVOICE,$tagStr)); + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { + + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = invoice.ID AND zbstl_tagid IN (%s)) = 0)', array( ZBS_TYPE_INVOICE, $tagStr ) ); + + } + } - } + #} ============ / WHERE =============== - } + #} ============ SORT ============== - + // Obj Model based sort conversion + // converts 'addr1' => 'zbsco_addr1' generically + if ( isset( $this->objectModel[ $sortByField ] ) && isset( $this->objectModel[ $sortByField ]['fieldname'] ) ) { + $sortByField = $this->objectModel[ $sortByField ]['fieldname']; + } - #} ============ / WHERE =============== + // Mapped sorts + // This catches listview and other exception sort cases + $sort_map = array( - #} ============ SORT ============== + // field aliases + 'ref' => 'zbsi_id_override', + 'value' => 'zbsi_total', - // Obj Model based sort conversion - // converts 'addr1' => 'zbsco_addr1' generically - if (isset($this->objectModel[$sortByField]) && isset($this->objectModel[$sortByField]['fieldname'])) $sortByField = $this->objectModel[$sortByField]['fieldname']; + // Note: "customer" here could be company or contact, so it's not a true sort (as no great way of doing this beyond some sort of prefix comparing) + 'customer' => '(SELECT ID FROM ' . $ZBSCRM_t['contacts'] . ' WHERE ID IN (SELECT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_from = invoice.ID))', - // Mapped sorts - // This catches listview and other exception sort cases - $sort_map = array( + ); - // field aliases - 'ref' => 'zbsi_id_override', - 'value' => 'zbsi_total', + if ( array_key_exists( $sortByField, $sort_map ) ) { - // Note: "customer" here could be company or contact, so it's not a true sort (as no great way of doing this beyond some sort of prefix comparing) - 'customer' => '(SELECT ID FROM '.$ZBSCRM_t['contacts'].' WHERE ID IN (SELECT zbsol_objid_to FROM '.$ZBSCRM_t['objlinks'].' WHERE zbsol_objtype_from = '.ZBS_TYPE_INVOICE.' AND zbsol_objtype_to = '.ZBS_TYPE_CONTACT.' AND zbsol_objid_from = invoice.ID))', + $sortByField = $sort_map[ $sortByField ]; - ); - - if ( array_key_exists( $sortByField, $sort_map ) ) { + } - $sortByField = $sort_map[ $sortByField ]; + #} ============ / SORT ============== - } + #} CHECK this + reset to default if faulty + if ( ! in_array( $whereCase, array( 'AND', 'OR' ) ) ) { + $whereCase = 'AND'; + } - #} ============ / SORT ============== + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params, $whereCase ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'contact' ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + try { - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'contact'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); - - try { + #} Catch count + return if requested + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } - #} Prep & run query - $queryObj = $this->prepare($query,$params); + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - #} Catch count + return if requested - if ($count) return $wpdb->get_var($queryObj); + } catch ( Exception $e ) { - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} General SQL Err + $this->catchSQLError( $e ); - } catch (Exception $e){ + } - #} General SQL Err - $this->catchSQLError($e); + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - } + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + // using onlyColumns filter? + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // using onlyColumns filter? - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + // only coumns return. + $resArr = array(); + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - // only coumns return. - $resArr = array(); - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + if ( isset( $resDataLine->$colDBKey ) ) { + $resArr[ $colStr ] = $resDataLine->$colDBKey; + } + } + } else { - if (isset($resDataLine->$colDBKey)) $resArr[$colStr] = $resDataLine->$colDBKey; + // tidy + $resArr = $this->tidy_invoice( $resDataLine, $withCustomFields ); - } + } + if ( $withLineItems ) { - } else { - - // tidy - $resArr = $this->tidy_invoice($resDataLine,$withCustomFields); + // add all line item lines + $resArr['lineitems'] = $this->DAL()->lineitems->getLineitems( + array( + 'associatedObjType' => ZBS_TYPE_INVOICE, + 'associatedObjID' => $resDataLine->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LINEITEM ), + ) + ); - } + } + if ( $withTransactions ) { - if ($withLineItems){ + // add all line item lines + $resArr['transactions'] = $this->DAL()->transactions->getTransactions( + array( + 'assignedInvoice' => $resDataLine->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), + ) + ); - // add all line item lines - $resArr['lineitems'] = $this->DAL()->lineitems->getLineitems(array('associatedObjType'=>ZBS_TYPE_INVOICE,'associatedObjID'=>$resDataLine->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LINEITEM))); - - } + } - if ($withTransactions){ + if ( $withTags ) { - // add all line item lines - $resArr['transactions'] = $this->DAL()->transactions->getTransactions(array('assignedInvoice'=>$resDataLine->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION))); - - } + // add all tags lines + $resArr['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_INVOICE, + 'objid' => $resDataLine->ID, + ) + ); - if ($withTags){ + } - // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_INVOICE,'objid'=>$resDataLine->ID)); + if ( $withOwner ) { - } + $resArr['owner'] = zeroBS_getOwner( $resDataLine->ID, true, ZBS_TYPE_INVOICE, $resDataLine->zbs_owner ); - if ($withOwner){ + } - $resArr['owner'] = zeroBS_getOwner($resDataLine->ID,true,ZBS_TYPE_INVOICE,$resDataLine->zbs_owner); + if ( $withAssigned ) { + + /* + This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + + // add all assigned contacts/companies + $res['contacts'] = $this->DAL()->contacts->getContacts(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + + $res['companies'] = $this->DAL()->companies->getCompanies(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + + .. but we use 1:1, at least now: */ + + // add all assigned contacts/companies + $resArr['contact'] = $this->DAL()->contacts->getContacts( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo' => $resDataLine->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); + + $resArr['company'] = $this->DAL()->companies->getCompanies( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo' => $resDataLine->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); - } + } - if ($withAssigned){ + if ( $withFiles ) { - /* This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + $resArr['files'] = zeroBSCRM_files_getFiles( 'invoice', $resDataLine->ID ); - // add all assigned contacts/companies - $res['contacts'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + } - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + if ( $withTotals ) { - .. but we use 1:1, at least now: */ + // add all tags lines + $resArr['totals'] = $this->generateTotalsTable( $resArr ); - // add all assigned contacts/companies - $resArr['contact'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + } - $resArr['company'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + $res[] = $resArr; - - } + } + } - if ($withFiles){ + return $res; + } - $resArr['files'] = zeroBSCRM_files_getFiles('invoice',$resDataLine->ID); - - } + /** + * Returns a count of invoices (owned) + * .. inc by status + * + * @return int count + */ + public function getInvoiceCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'withStatus' => false, // will be str if used + + // permissions + 'ignoreowner' => true, // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - if ($withTotals){ + $whereArr = array(); - // add all tags lines - $resArr['totals'] = $this->generateTotalsTable($resArr); + if ( $withStatus !== false && ! empty( $withStatus ) ) { + $whereArr['status'] = array( 'zbsi_status', '=', '%s', $withStatus ); + } - } + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_INVOICE, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + } - $res[] = $resArr; + /** + * adds or updates a invoice object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateInvoice( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} Retrieve any cf + $customFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_INVOICE ) ); + // not req. here$addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'owner' => -1, + + // fields (directly) + 'data' => array( + + 'id_override' => '', + 'parent' => '', + 'status' => '', + 'hash' => '', + 'pdf_template' => '', + 'portal_template' => '', + 'email_template' => '', + 'invoice_frequency' => '', + 'currency' => '', + 'pay_via' => '', + 'logo_url' => '', + 'address_to_objtype' => '', + 'addressed_from' => '', + 'addressed_to' => '', + 'allow_partial' => -1, + 'allow_tip' => -1, + 'send_attachments' => -1, + 'hours_or_quantity' => '', + 'date' => '', + 'due_date' => '', + 'paid_date' => '', + 'hash_viewed' => '', + 'hash_viewed_count' => '', + 'portal_viewed' => '', + 'portal_viewed_count' => '', + 'net' => '', + 'discount' => '', + 'discount_type' => '', + 'shipping' => '', + 'shipping_taxes' => '', + 'shipping_tax' => '', + 'taxes' => '', + 'tax' => '', + 'total' => '', + + // lineitems: + 'lineitems' => false, + // will be an array of lineitem lines (as per matching lineitem database model) + // note: if no change desired, pass "false" + // if removal of all/change, pass empty array + + // obj links: + 'contacts' => false, // array of id's + 'companies' => false, // array of id's + + // Note Custom fields may be passed here, but will not have defaults so check isset() + + // tags + 'tags' => -1, // pass an array of tag ids or tag strings + 'tag_mode' => 'replace', // replace|append|remove + + 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) + + 'created' => -1, + 'lastupdated' => '', + + ), + + 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')). the key needs to match the DB table, i.e. zbsi_status and not + // just status. For full key references see developer docs (link to follow). + + // this function as DAL1 func did. + 'extraMeta' => -1, + 'automatorPassthrough' => -1, + + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newInvoice (because is migrating, not creating new :) this was -1 before + + 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + + 'calculate_totals' => false, // This allows us to recalculate tax, subtotal, total via php (e.g. if added via api). Only works if not using limitedFields + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } - } - } + // Needs this to grab custom fields (if passed) too :) + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { + // only for data, limited fields below + if ( is_array( $data ) ) { + if ( isset( $args['data'][ $cK ] ) ) { + $data[ $cK ] = $args['data'][ $cK ]; + } + } + } + } - return $res; - } + // this takes limited fields + checks through for custom fields present + // (either as key zbsi_source or source, for example) + // then switches them into the $data array, for separate update + // where this'll fall over is if NO normal contact data is sent to update, just custom fields + if ( is_array( $limitedFields ) && is_array( $customFields ) ) { + // $customFieldKeys = array_keys($customFields); + $newLimitedFields = array(); + // cycle through + foreach ( $limitedFields as $field ) { - /** - * Returns a count of invoices (owned) - * .. inc by status - * - * @return int count - */ - public function getInvoiceCount($args=array()){ - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // Search/Filtering (leave as false to ignore) - 'withStatus' => false, // will be str if used - - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - $whereArr = array(); - - if ($withStatus !== false && !empty($withStatus)) $whereArr['status'] = array('zbsi_status','=','%s',$withStatus); - - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_INVOICE, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - } - - - /** - * adds or updates a invoice object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateInvoice($args=array()){ - - global $ZBSCRM_t,$wpdb,$zbs; - - #} Retrieve any cf - $customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_INVOICE)); - // not req. here$addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - 'owner' => -1, - - // fields (directly) - 'data' => array( - - - 'id_override' => '', - 'parent' => '', - 'status' => '', - 'hash' => '', - 'pdf_template' => '', - 'portal_template' => '', - 'email_template' => '', - 'invoice_frequency' => '', - 'currency' => '', - 'pay_via' => '', - 'logo_url' => '', - 'address_to_objtype' => '', - 'addressed_from' => '', - 'addressed_to' => '', - 'allow_partial' => -1, - 'allow_tip' => -1, - 'send_attachments' => -1, - 'hours_or_quantity' => '', - 'date' => '', - 'due_date' => '', - 'paid_date' => '', - 'hash_viewed' => '', - 'hash_viewed_count' => '', - 'portal_viewed' => '', - 'portal_viewed_count' => '', - 'net' => '', - 'discount' => '', - 'discount_type' => '', - 'shipping' => '', - 'shipping_taxes' => '', - 'shipping_tax' => '', - 'taxes' => '', - 'tax' => '', - 'total' => '', - - // lineitems: - 'lineitems' => false, - // will be an array of lineitem lines (as per matching lineitem database model) - // note: if no change desired, pass "false" - // if removal of all/change, pass empty array - - // obj links: - 'contacts' => false, // array of id's - 'companies' => false, // array of id's - - // Note Custom fields may be passed here, but will not have defaults so check isset() - - // tags - 'tags' => -1, // pass an array of tag ids or tag strings - 'tag_mode' => 'replace', // replace|append|remove - - 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) - - 'created' => -1, - 'lastupdated' => '', - - ), - - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) - // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')). the key needs to match the DB table, i.e. zbsi_status and not - // just status. For full key references see developer docs (link to follow). - - // this function as DAL1 func did. - 'extraMeta' => -1, - 'automatorPassthrough' => -1, - - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newInvoice (because is migrating, not creating new :) this was -1 before - - 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) - - 'calculate_totals' => false // This allows us to recalculate tax, subtotal, total via php (e.g. if added via api). Only works if not using limitedFields - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - - // Needs this to grab custom fields (if passed) too :) - if ( is_array( $customFields ) ) { - foreach ( $customFields as $cK => $cF ) { - // only for data, limited fields below - if ( is_array( $data ) ) { - if ( isset( $args['data'][$cK] ) ) { - $data[$cK] = $args['data'][$cK]; - } - } - } - - } - - // this takes limited fields + checks through for custom fields present - // (either as key zbsi_source or source, for example) - // then switches them into the $data array, for separate update - // where this'll fall over is if NO normal contact data is sent to update, just custom fields - if (is_array($limitedFields) && is_array($customFields)){ - - //$customFieldKeys = array_keys($customFields); - $newLimitedFields = array(); - - // cycle through - foreach ($limitedFields as $field){ - - // some weird case where getting empties, so added check - if (isset($field['key']) && !empty($field['key'])){ + // some weird case where getting empties, so added check + if ( isset( $field['key'] ) && ! empty( $field['key'] ) ) { $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase if ( str_starts_with( $field['key'], 'zbsi_' ) ) { $dePrefixed = substr( $field['key'], strlen( 'zbsi_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - if (isset($customFields[$field['key']])){ - - // is custom, move to data - $data[$field['key']] = $field['val']; + if ( isset( $customFields[ $field['key'] ] ) ) { - } else if (!empty($dePrefixed) && isset($customFields[$dePrefixed])){ + // is custom, move to data + $data[ $field['key'] ] = $field['val']; - // is custom, move to data - $data[$dePrefixed] = $field['val']; + } elseif ( ! empty( $dePrefixed ) && isset( $customFields[ $dePrefixed ] ) ) { - } else { + // is custom, move to data + $data[ $dePrefixed ] = $field['val']; - // add it to limitedFields (it's not dealt with post-update) - $newLimitedFields[] = $field; - } - } - } - - // move this back in - $limitedFields = $newLimitedFields; - unset($newLimitedFields); - - } + } else { - #} =========== / LOAD ARGS ============ + // add it to limitedFields (it's not dealt with post-update) + $newLimitedFields[] = $field; + } + } + } - #} ========== CHECK FIELDS ============ - - $id = (int)$id; - - // here we check that the potential owner CAN even own - if ($owner > 0 && !user_can($owner,'admin_zerobs_usr')) $owner = -1; + // move this back in + $limitedFields = $newLimitedFields; + unset( $newLimitedFields ); - // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } + } + #} =========== / LOAD ARGS ============ - if (is_array($limitedFields)){ + #} ========== CHECK FIELDS ============ - // LIMITED UPDATE (only a few fields.) - if (!is_array($limitedFields) || count ($limitedFields) <= 0) return false; - // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; + $id = (int) $id; - } else { + // here we check that the potential owner CAN even own + if ( $owner > 0 && ! user_can( $owner, 'admin_zerobs_usr' ) ) { + $owner = -1; + } - // NORMAL, FULL UPDATE + // if owner = -1, add current + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); } - } + if ( is_array( $limitedFields ) ) { + // LIMITED UPDATE (only a few fields.) + if ( ! is_array( $limitedFields ) || count( $limitedFields ) <= 0 ) { + return false; + } + // REQ. ID too (can only update) + if ( empty( $id ) || $id <= 0 ) { + return false; + } + } else { - #} If no status, and default is specified in settings, add that in :) - if (is_null($data['status']) || !isset($data['status']) || empty($data['status'])){ + // NORMAL, FULL UPDATE - // Default status for obj? -> this one gets for contacts -> $zbsCustomerMeta['status'] = zeroBSCRM_getSetting('defaultstatus'); - // For now we force 'Draft' - $data['status'] = __('Draft','zero-bs-crm'); - } + } - #} ========= / CHECK FIELDS =========== + #} If no status, and default is specified in settings, add that in :) + if ( $data['status'] === null || ! isset( $data['status'] ) || empty( $data['status'] ) ) { + // Default status for obj? -> this one gets for contacts -> $zbsCustomerMeta['status'] = zeroBSCRM_getSetting('defaultstatus'); + // For now we force 'Draft' + $data['status'] = __( 'Draft', 'zero-bs-crm' ); + } - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== + #} ========= / CHECK FIELDS =========== - // this only functions if externalsource is set (e.g. api/form, etc.) - if (isset($data['externalSources']) && is_array($data['externalSources']) && count($data['externalSources']) > 0) { - if (zeroBSCRM_getSetting('fieldoverride') == "1"){ + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - $do_not_update_blanks = true; + // this only functions if externalsource is set (e.g. api/form, etc.) + if ( isset( $data['externalSources'] ) && is_array( $data['externalSources'] ) && count( $data['externalSources'] ) > 0 ) { + if ( zeroBSCRM_getSetting( 'fieldoverride' ) == '1' ) { - } + $do_not_update_blanks = true; - } + } + } - // either ext source + setting, or set by the func call - if ($do_not_update_blanks){ + // either ext source + setting, or set by the func call + if ( $do_not_update_blanks ) { - // this setting says 'don't override filled-out data with blanks' - // so here we check through any passed blanks + convert to limitedFields - // only matters if $id is set (there is somt to update not add - if (isset($id) && !empty($id) && $id > 0){ + // this setting says 'don't override filled-out data with blanks' + // so here we check through any passed blanks + convert to limitedFields + // only matters if $id is set (there is somt to update not add + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_invoice($data); - //unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue - //unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_invoice( $data ); + // unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue + // unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - $origData = $data; //$data = array(); - $limitedData = array(); // array(array('key'=>'zbsi_x','val'=>y,'type'=>'%s')) + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbsi_x','val'=>y,'type'=>'%s')) - // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) - // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates - foreach ($dbData as $k => $v){ + // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) + // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates + foreach ( $dbData as $k => $v ) { - $intV = (int)$v; + $intV = (int) $v; - // only add if valuenot empty - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { - // add to update arr - $limitedData[] = array( - 'key' => 'zbsi_'.$k, // we have to add zbsi_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbsi_'.$k) - ); + // add to update arr + $limitedData[] = array( + 'key' => 'zbsi_' . $k, // we have to add zbsi_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbsi_' . $k ), + ); - // add to remade $data for post-update updates - $data[$k] = $v; + // add to remade $data for post-update updates + $data[ $k ] = $v; - } + } + } - } + // copy over + $limitedFields = $limitedData; - // copy over - $limitedFields = $limitedData; + } // / if ID - } // / if ID + } // / if do_not_update_blanks - } // / if do_not_update_blanks + #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== - #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== + #} ========= BUILD DATA =========== - #} ========= BUILD DATA =========== + $update = false; + $dataArr = array(); + $typeArr = array(); - $update = false; $dataArr = array(); $typeArr = array(); + if ( is_array( $limitedFields ) ) { - if (is_array($limitedFields)){ + // LIMITED FIELDS + $update = true; - // LIMITED FIELDS - $update = true; + // cycle through + foreach ( $limitedFields as $field ) { - // cycle through - foreach ($limitedFields as $field){ + // some weird case where getting empties, so added check + if ( ! empty( $field['key'] ) ) { + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } + } - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } + // add update time + if ( ! isset( $dataArr['zbsi_lastupdated'] ) ) { + $dataArr['zbsi_lastupdated'] = time(); + $typeArr[] = '%d'; } + } else { - } + // FULL UPDATE/INSERT - // add update time - if (!isset($dataArr['zbsi_lastupdated'])){ $dataArr['zbsi_lastupdated'] = time(); $typeArr[] = '%d'; } + // (re)calculate the totals etc? + if ( $calculate_totals ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } else { + $data = $this->recalculate( $data ); - // FULL UPDATE/INSERT + } - // (re)calculate the totals etc? - if ( $calculate_totals ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + // contacts - avoid dupes + if ( isset( $data['contacts'] ) && is_array( $data['contacts'] ) ) { - $data = $this->recalculate($data); + $coArr = array(); + foreach ( $data['contacts'] as $c ) { + $cI = (int) $c; + if ( $cI > 0 && ! in_array( $cI, $coArr ) ) { + $coArr[] = $cI; + } + } - } - - // contacts - avoid dupes - if (isset($data['contacts']) && is_array($data['contacts'])){ - - $coArr = array(); - foreach ($data['contacts'] as $c){ - $cI = (int)$c; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; - } - - // reset the main - if (count($coArr) > 0) - $data['contacts'] = $coArr; - else - $data['contacts'] = 'unset'; - unset($coArr); - - } - - // companies - avoid dupes - if (isset($data['companies']) && is_array($data['companies'])){ - - $coArr = array(); - foreach ($data['companies'] as $c){ - $cI = (int)$c; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; - } - - // reset the main - if (count($coArr) > 0) - $data['companies'] = $coArr; - else - $data['companies'] = 'unset'; - unset($coArr); - - } - - // UPDATE - $dataArr = array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, - - - 'zbsi_id_override' => $data['id_override'], - 'zbsi_parent' => $data['parent'], - 'zbsi_status' => $data['status'], - 'zbsi_hash' => $data['hash'], - 'zbsi_pdf_template' => $data['pdf_template'], - 'zbsi_portal_template' => $data['portal_template'], - 'zbsi_email_template' => $data['email_template'], - 'zbsi_invoice_frequency' => $data['invoice_frequency'], - 'zbsi_currency' => $data['currency'], - 'zbsi_pay_via' => $data['pay_via'], - 'zbsi_logo_url' => $data['logo_url'], - 'zbsi_address_to_objtype' => $data['address_to_objtype'], - 'zbsi_addressed_from' => $data['addressed_from'], - 'zbsi_addressed_to' => $data['addressed_to'], - 'zbsi_allow_partial' => $data['allow_partial'], - 'zbsi_allow_tip' => $data['allow_tip'], - 'zbsi_send_attachments' => $data['send_attachments'], - 'zbsi_hours_or_quantity' => $data['hours_or_quantity'], - 'zbsi_date' => $data['date'], - 'zbsi_due_date' => $data['due_date'], - 'zbsi_paid_date' => $data['paid_date'], - 'zbsi_hash_viewed' => $data['hash_viewed'], - 'zbsi_hash_viewed_count' => $data['hash_viewed_count'], - 'zbsi_portal_viewed' => $data['portal_viewed'], - 'zbsi_portal_viewed_count' => $data['portal_viewed_count'], - 'zbsi_net' => $data['net'], - 'zbsi_discount' => $data['discount'], - 'zbsi_discount_type' => $data['discount_type'], - 'zbsi_shipping' => $data['shipping'], - 'zbsi_shipping_taxes' => $data['shipping_taxes'], - 'zbsi_shipping_tax' => $data['shipping_tax'], - 'zbsi_taxes' => $data['taxes'], - 'zbsi_tax' => $data['tax'], - 'zbsi_total' => $data['total'], - 'zbsi_lastupdated' => time(), - - ); - - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner - - - '%s', // id_override - '%d', // parent - '%s', // status - '%s', // hash - '%s', // pdf template - '%s', // portal template - '%s', // email template - '%d', // zbsi_invoice_frequency - '%s', // curr - '%d', // pay via - '%s', // logo url - '%d', // addr to obj type - '%s', // addr from - '%s', // addr to - '%d', // zbsi_allow_partial - '%d', // allow_tip - '%d', // hours or quantity - '%d', // zbsi_send_attachments - '%d', // date - '%d', // due date - '%d', // paid date - '%d', // hash viewed - '%d', // hash viewed count - '%d', // portal viewed - '%d', // portal viewed count - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%d', - - ); - - - - - if (!empty($id) && $id > 0){ - - // is update - $update = true; - - } else { - - // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $typeArr[] = '%d'; - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbsi_created'] = $data['created'];$typeArr[] = '%d'; - } else { - $dataArr['zbsi_created'] = time(); $typeArr[] = '%d'; - } - - } - - // if a blank hash is passed, generate a new one - if (isset($dataArr['zbsi_hash']) && $dataArr['zbsi_hash'] == '') $dataArr['zbsi_hash'] = zeroBSCRM_generateHash(20); - - } - - #} ========= / BUILD DATA =========== - - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== - - // if we're passing limitedFields we skip these, for now - // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ - - // verify uniques - if (!$this->verifyUniqueValues($data,$id)) return false; // / fails unique field verify - - // verify not_empty - if (!$this->verifyNonEmptyValues($data)) return false; // / fails empty field verify - - } - - // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks($dataArr); - - #} ========= / CHECK force_uniques & not_empty ================ - #} ============================================================ - - - #} Check if ID present - if ($update){ - - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - $originalStatus = $this->getInvoiceStatus($id); + // reset the main + if ( count( $coArr ) > 0 ) { + $data['contacts'] = $coArr; + } else { + $data['contacts'] = 'unset'; + } + unset( $coArr ); - $previous_invoice_obj = $this->getInvoice( $id ); + } - // log any change of status - if (isset($dataArr['zbsi_status']) && !empty($dataArr['zbsi_status']) && !empty($originalStatus) && $dataArr['zbsi_status'] != $originalStatus){ + // companies - avoid dupes + if ( isset( $data['companies'] ) && is_array( $data['companies'] ) ) { - // status change - $statusChange = array( - 'from' => $originalStatus, - 'to' => $dataArr['zbsi_status'] - ); - } + $coArr = array(); + foreach ( $data['companies'] as $c ) { + $cI = (int) $c; + if ( $cI > 0 && ! in_array( $cI, $coArr ) ) { + $coArr[] = $cI; + } + } - // If we are using our CRM reference id (table field id_override) system, we should not change the reference number when importing from woo. - if ( isset( $data['woo_use_crm_id'] ) && $data['woo_use_crm_id'] === true ) { - $dataArr['zbsi_id_override'] = $previous_invoice_obj['id_override']; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // reset the main + if ( count( $coArr ) > 0 ) { + $data['companies'] = $coArr; + } else { + $data['companies'] = 'unset'; } + unset( $coArr ); - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['invoices'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ + } + // UPDATE + $dataArr = array( + + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, + + 'zbsi_id_override' => $data['id_override'], + 'zbsi_parent' => $data['parent'], + 'zbsi_status' => $data['status'], + 'zbsi_hash' => $data['hash'], + 'zbsi_pdf_template' => $data['pdf_template'], + 'zbsi_portal_template' => $data['portal_template'], + 'zbsi_email_template' => $data['email_template'], + 'zbsi_invoice_frequency' => $data['invoice_frequency'], + 'zbsi_currency' => $data['currency'], + 'zbsi_pay_via' => $data['pay_via'], + 'zbsi_logo_url' => $data['logo_url'], + 'zbsi_address_to_objtype' => $data['address_to_objtype'], + 'zbsi_addressed_from' => $data['addressed_from'], + 'zbsi_addressed_to' => $data['addressed_to'], + 'zbsi_allow_partial' => $data['allow_partial'], + 'zbsi_allow_tip' => $data['allow_tip'], + 'zbsi_send_attachments' => $data['send_attachments'], + 'zbsi_hours_or_quantity' => $data['hours_or_quantity'], + 'zbsi_date' => $data['date'], + 'zbsi_due_date' => $data['due_date'], + 'zbsi_paid_date' => $data['paid_date'], + 'zbsi_hash_viewed' => $data['hash_viewed'], + 'zbsi_hash_viewed_count' => $data['hash_viewed_count'], + 'zbsi_portal_viewed' => $data['portal_viewed'], + 'zbsi_portal_viewed_count' => $data['portal_viewed_count'], + 'zbsi_net' => $data['net'], + 'zbsi_discount' => $data['discount'], + 'zbsi_discount_type' => $data['discount_type'], + 'zbsi_shipping' => $data['shipping'], + 'zbsi_shipping_taxes' => $data['shipping_taxes'], + 'zbsi_shipping_tax' => $data['shipping_tax'], + 'zbsi_taxes' => $data['taxes'], + 'zbsi_tax' => $data['tax'], + 'zbsi_total' => $data['total'], + 'zbsi_lastupdated' => time(), - // if passing limitedFields instead of data, we ignore the following - // this doesn't work, because data is in args default as arr - //if (isset($data) && is_array($data)){ - // so... - if (!isset($limitedFields) || !is_array($limitedFields) || $limitedFields == -1){ + ); - // Line Items ==== + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner + + '%s', // id_override + '%d', // parent + '%s', // status + '%s', // hash + '%s', // pdf template + '%s', // portal template + '%s', // email template + '%d', // zbsi_invoice_frequency + '%s', // curr + '%d', // pay via + '%s', // logo url + '%d', // addr to obj type + '%s', // addr from + '%s', // addr to + '%d', // zbsi_allow_partial + '%d', // allow_tip + '%d', // hours or quantity + '%d', // zbsi_send_attachments + '%d', // date + '%d', // due date + '%d', // paid date + '%d', // hash viewed + '%d', // hash viewed count + '%d', // portal viewed + '%d', // portal viewed count + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%d', - // line item work - if (isset($data['lineitems']) && is_array($data['lineitems'])){ + ); - // if array passed, update, even if removing - if (count($data['lineitems']) > 0){ + if ( ! empty( $id ) && $id > 0 ) { - // passed, for now this is BRUTAL and just clears old ones + readds - // once live, discuss how to refactor to be less brutal. + // is update + $update = true; - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$id,'objType'=>ZBS_TYPE_INVOICE)); + } else { - // addupdate each - foreach ($data['lineitems'] as $lineitem) { + // INSERT (get's few extra :D) + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbsi_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbsi_created'] = time(); + $typeArr[] = '%d'; + } + } - // slight rejig of passed so works cleanly with data array style - $lineItemID = false; if (isset($lineitem['ID'])) $lineItemID = $lineitem['ID']; - $this->DAL()->lineitems->addUpdateLineitem(array( - 'id'=>$lineItemID, - 'linkedObjType' => ZBS_TYPE_INVOICE, - 'linkedObjID' => $id, - 'data'=>$lineitem, - 'calculate_totals' => true - )); + // if a blank hash is passed, generate a new one + if ( isset( $dataArr['zbsi_hash'] ) && $dataArr['zbsi_hash'] == '' ) { + $dataArr['zbsi_hash'] = zeroBSCRM_generateHash( 20 ); + } + } - } + #} ========= / BUILD DATA =========== - } else { + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$id,'objType'=>ZBS_TYPE_INVOICE)); + // if we're passing limitedFields we skip these, for now + // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 + if ( ! is_array( $limitedFields ) ) { - } + // verify uniques + if ( ! $this->verifyUniqueValues( $data, $id ) ) { + return false; // / fails unique field verify + } + // verify not_empty + if ( ! $this->verifyNonEmptyValues( $data ) ) { + return false; // / fails empty field verify + } + } - } + // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections + $dataArr = $this->wpdbChecks( $dataArr ); - // / Line Items ==== + #} ========= / CHECK force_uniques & not_empty ================ + #} ============================================================ - // OBJ LINKS - to contacts/companies - if (!is_array($data['contacts'])) - $this->addUpdateObjectLinks($id,'unset',ZBS_TYPE_CONTACT); - else - $this->addUpdateObjectLinks($id,$data['contacts'],ZBS_TYPE_CONTACT); - if (!is_array($data['companies'])) - $this->addUpdateObjectLinks($id,'unset',ZBS_TYPE_COMPANY); - else - $this->addUpdateObjectLinks($id,$data['companies'],ZBS_TYPE_COMPANY); + #} Check if ID present + if ( $update ) { - // IA also gets 'againstid' historically, but we'll pass as 'against id's' - $againstIDs = array('contacts'=>$data['contacts'],'companies'=>$data['companies']); + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) + $originalStatus = $this->getInvoiceStatus( $id ); - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + $previous_invoice_obj = $this->getInvoice( $id ); - $this->addUpdateInvoiceTags( - array( - 'id' => $id, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + // log any change of status + if ( isset( $dataArr['zbsi_status'] ) && ! empty( $dataArr['zbsi_status'] ) && ! empty( $originalStatus ) && $dataArr['zbsi_status'] != $originalStatus ) { - } + // status change + $statusChange = array( + 'from' => $originalStatus, + 'to' => $dataArr['zbsi_status'], + ); + } - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( - array( - 'obj_id' => $id, - 'obj_type_id' => ZBS_TYPE_INVOICE, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), - ) - ); // for IA below + // If we are using our CRM reference id (table field id_override) system, we should not change the reference number when importing from woo. + if ( isset( $data['woo_use_crm_id'] ) && $data['woo_use_crm_id'] === true ) { + $dataArr['zbsi_id_override'] = $previous_invoice_obj['id_override']; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - // Custom fields? + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['invoices'], + $dataArr, + array( // where + 'ID' => $id, + ), + $typeArr, + array( // where data types + '%d', + ) + ) !== false ) { + + // if passing limitedFields instead of data, we ignore the following + // this doesn't work, because data is in args default as arr + // if (isset($data) && is_array($data)){ + // so... + if ( ! isset( $limitedFields ) || ! is_array( $limitedFields ) || $limitedFields == -1 ) { + + // Line Items ==== + + // line item work + if ( isset( $data['lineitems'] ) && is_array( $data['lineitems'] ) ) { + + // if array passed, update, even if removing + if ( count( $data['lineitems'] ) > 0 ) { + + // passed, for now this is BRUTAL and just clears old ones + readds + // once live, discuss how to refactor to be less brutal. + + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $id, + 'objType' => ZBS_TYPE_INVOICE, + ) + ); + + // addupdate each + foreach ( $data['lineitems'] as $lineitem ) { + + // slight rejig of passed so works cleanly with data array style + $lineItemID = false; + if ( isset( $lineitem['ID'] ) ) { + $lineItemID = $lineitem['ID']; + } + $this->DAL()->lineitems->addUpdateLineitem( + array( + 'id' => $lineItemID, + 'linkedObjType' => ZBS_TYPE_INVOICE, + 'linkedObjID' => $id, + 'data' => $lineitem, + 'calculate_totals' => true, + ) + ); - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + } + } else { - // any? - if (isset($data[$cK])){ + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $id, + 'objType' => ZBS_TYPE_INVOICE, + ) + ); - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_INVOICE, - 'objid' => $id, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + } + } - } + // / Line Items ==== - } + // OBJ LINKS - to contacts/companies + if ( ! is_array( $data['contacts'] ) ) { + $this->addUpdateObjectLinks( $id, 'unset', ZBS_TYPE_CONTACT ); + } else { + $this->addUpdateObjectLinks( $id, $data['contacts'], ZBS_TYPE_CONTACT ); + } + if ( ! is_array( $data['companies'] ) ) { + $this->addUpdateObjectLinks( $id, 'unset', ZBS_TYPE_COMPANY ); + } else { + $this->addUpdateObjectLinks( $id, $data['companies'], ZBS_TYPE_COMPANY ); + } - // / Custom Fields + // IA also gets 'againstid' historically, but we'll pass as 'against id's' + $againstIDs = array( + 'contacts' => $data['contacts'], + 'companies' => $data['companies'], + ); - } // / if $data + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $this->addUpdateInvoiceTags( + array( + 'id' => $id, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); - $confirmedExtraMeta = array(); + } - foreach ($extraMeta as $k => $v){ + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $id, + 'obj_type_id' => ZBS_TYPE_INVOICE, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below + + // Custom fields? + + #} Cycle through + add/update if set + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { + + // any? + if ( isset( $data[ $cK ] ) ) { + + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_INVOICE, + 'objid' => $id, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + } + } + } - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_INVOICE,$id,'extra_'.$cleanKey,$v); + // / Custom Fields - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + } // / if $data - } + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } + $confirmedExtraMeta = array(); + foreach ( $extraMeta as $k => $v ) { - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - // catch dirty flag (update of status) (note, after update_post_meta - as separate) - //if (isset($_POST['zbsi_status_dirtyflag']) && $_POST['zbsi_status_dirtyflag'] == "1"){ - // actually here, it's set above - if (isset($statusChange) && is_array($statusChange)){ + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_INVOICE, $id, 'extra_' . $cleanKey, $v ); - // status has changed + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - // IA - zeroBSCRM_FireInternalAutomator('invoice.status.update',array( - 'id'=>$id, - 'againstids'=>array(), //$againstIDs, - 'data'=> $data, - 'from' => $statusChange['from'], - 'to' => $statusChange['to'] - )); + } + } - } + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // UPDATING CONTACT + if ( ! $silentInsert ) { + + // catch dirty flag (update of status) (note, after update_post_meta - as separate) + // if (isset($_POST['zbsi_status_dirtyflag']) && $_POST['zbsi_status_dirtyflag'] == "1"){ + // actually here, it's set above + if ( isset( $statusChange ) && is_array( $statusChange ) ) { + + // status has changed + + // IA + zeroBSCRM_FireInternalAutomator( + 'invoice.status.update', + array( + 'id' => $id, + 'againstids' => array(), // $againstIDs, + 'data' => $data, + 'from' => $statusChange['from'], + 'to' => $statusChange['to'], + ) + ); + } - // IA General invoice update (2.87+) - zeroBSCRM_FireInternalAutomator('invoice.update',array( - 'id'=>$id, - 'data'=>$data, - 'againstids'=>array(), //$againstIDs, - 'extsource'=>false, //$approvedExternalSource - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta' => $confirmedExtraMeta, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase -- Also this is the "extraMeta" passed (as saved) - 'prev_invoice' => $previous_invoice_obj, - )); + // IA General invoice update (2.87+) + zeroBSCRM_FireInternalAutomator( + 'invoice.update', + array( + 'id' => $id, + 'data' => $data, + 'againstids' => array(), // $againstIDs, + 'extsource' => false, // $approvedExternalSource + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase -- Also this is the "extraMeta" passed (as saved) + 'prev_invoice' => $previous_invoice_obj, + ) + ); + + $data['id'] = $id; + $previous_invoice_obj['id'] = $id; + + $this->events_manager->invoice()->updated( $data, $previous_invoice_obj ); - $data['id'] = $id; - $previous_invoice_obj['id'] = $id; + } - $this->events_manager->invoice()->updated( $data, $previous_invoice_obj ); + // Successfully updated - Return id + return $id; - } + } else { - - // Successfully updated - Return id - return $id; + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); + // FAILED update + return false; - // FAILED update - return false; + } + } else { + // If we are using our CRM reference id (table field id_override) system, we should generate a new invoice number. + if ( isset( $data['woo_use_crm_id'] ) && $data['woo_use_crm_id'] === true ) { + $ref_type = $zbs->settings->get( 'reftype' ); + // We can only generate it if autonumber is set + if ( $ref_type === 'autonumber' ) { + $next_number = $zbs->settings->get( 'refnextnum' ); + $dataArr['zbsi_id_override'] = $zbs->settings->get( 'refprefix' ) . $next_number . $zbs->settings->get( 'refsuffix' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + ++$next_number; + $zbs->settings->update( 'refnextnum', $next_number ); + } + } - } + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['invoices'], + $dataArr, + $typeArr + ) > 0 ) { - } else { - // If we are using our CRM reference id (table field id_override) system, we should generate a new invoice number. - if ( isset( $data['woo_use_crm_id'] ) && $data['woo_use_crm_id'] === true ) { - $ref_type = $zbs->settings->get( 'reftype' ); - // We can only generate it if autonumber is set - if ( $ref_type === 'autonumber' ) { - $next_number = $zbs->settings->get( 'refnextnum' ); - $dataArr['zbsi_id_override'] = $zbs->settings->get( 'refprefix' ) . $next_number . $zbs->settings->get( 'refsuffix' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - ++$next_number; - $zbs->settings->update( 'refnextnum', $next_number ); - } - } + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['invoices'], - $dataArr, - $typeArr ) > 0){ + // Line Items ==== - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; + // line item work + if ( isset( $data['lineitems'] ) && is_array( $data['lineitems'] ) ) { - // Line Items ==== + // if array passed, update, even if removing + if ( count( $data['lineitems'] ) > 0 ) { - // line item work - if (isset($data['lineitems']) && is_array($data['lineitems'])){ + // passed, for now this is BRUTAL and just clears old ones + readds + // once live, discuss how to refactor to be less brutal. - // if array passed, update, even if removing - if (count($data['lineitems']) > 0){ + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $newID, + 'objType' => ZBS_TYPE_INVOICE, + ) + ); - // passed, for now this is BRUTAL and just clears old ones + readds - // once live, discuss how to refactor to be less brutal. + // addupdate each + foreach ( $data['lineitems'] as $lineitem ) { - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$newID,'objType'=>ZBS_TYPE_INVOICE)); + // slight rejig of passed so works cleanly with data array style + $lineItemID = false; + if ( isset( $lineitem['ID'] ) ) { + $lineItemID = $lineitem['ID']; + } + $this->DAL()->lineitems->addUpdateLineitem( + array( + 'id' => $lineItemID, + 'linkedObjType' => ZBS_TYPE_INVOICE, + 'linkedObjID' => $newID, + 'data' => $lineitem, + 'calculate_totals' => true, + ) + ); - // addupdate each - foreach ($data['lineitems'] as $lineitem) { + } + } else { - // slight rejig of passed so works cleanly with data array style - $lineItemID = false; if (isset($lineitem['ID'])) $lineItemID = $lineitem['ID']; - $this->DAL()->lineitems->addUpdateLineitem(array( - 'id'=>$lineItemID, - 'linkedObjType' => ZBS_TYPE_INVOICE, - 'linkedObjID' => $newID, - 'data'=>$lineitem, - 'calculate_totals' => true - )); + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $newID, + 'objType' => ZBS_TYPE_INVOICE, + ) + ); - } + } + } - } else { + // / Line Items ==== - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$newID,'objType'=>ZBS_TYPE_INVOICE)); + // OBJ LINKS - to contacts/companies + $this->addUpdateObjectLinks( $newID, $data['contacts'], ZBS_TYPE_CONTACT ); + $this->addUpdateObjectLinks( $newID, $data['companies'], ZBS_TYPE_COMPANY ); + // IA also gets 'againstid' historically, but we'll pass as 'against id's' + $againstIDs = array( + 'contacts' => $data['contacts'], + 'companies' => $data['companies'], + ); - } + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { + $this->addUpdateInvoiceTags( + array( + 'id' => $newID, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); - } + } - // / Line Items ==== + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $newID, + 'obj_type_id' => ZBS_TYPE_INVOICE, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below + + // Custom fields? + + #} Cycle through + add/update if set + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { + + // any? + if ( isset( $data[ $cK ] ) ) { + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_INVOICE, + 'objid' => $newID, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); + } + } + } - // OBJ LINKS - to contacts/companies - $this->addUpdateObjectLinks($newID,$data['contacts'],ZBS_TYPE_CONTACT); - $this->addUpdateObjectLinks($newID,$data['companies'],ZBS_TYPE_COMPANY); - // IA also gets 'againstid' historically, but we'll pass as 'against id's' - $againstIDs = array('contacts'=>$data['contacts'],'companies'=>$data['companies']); + // / Custom Fields - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $this->addUpdateInvoiceTags( - array( - 'id' => $newID, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + $confirmedExtraMeta = array(); - } + foreach ( $extraMeta as $k => $v ) { - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( - array( - 'obj_id' => $newID, - 'obj_type_id' => ZBS_TYPE_INVOICE, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), - ) - ); // for IA below + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - // Custom fields? + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_INVOICE, $newID, 'extra_' . $cleanKey, $v ); - #} Cycle through + add/update if set - if ( is_array( $customFields ) ) { - foreach ( $customFields as $cK => $cF ) { + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - // any? - if ( isset( $data[$cK] ) ) { - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_INVOICE, - 'objid' => $newID, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); - } - } - } + } + } - // / Custom Fields + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // NEW CONTACT + if ( ! $silentInsert ) { + + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'invoice.new', + array( + 'id' => $newID, + 'data' => $data, + 'againstids' => $againstIDs, + 'extsource' => $approvedExternalSource, + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); + + $data['id'] = $newID; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $this->events_manager->invoice()->created( $data ); + } - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + return $newID; - $confirmedExtraMeta = array(); + } else { - foreach ($extraMeta as $k => $v){ + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + #} Failed to Insert + return false; - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_INVOICE,$newID,'extra_'.$cleanKey,$v); + } + } - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + return false; + } - } + /** + * adds or updates a invoice's tags + * ... this is really just a wrapper for addUpdateObjectTags + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateInvoiceTags( $args = array() ) { - } + global $ZBSCRM_t, $wpdb; - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT - if (!$silentInsert){ + #} ============ LOAD ARGS ============= + $defaultArgs = array( - #} Add to automator - zeroBSCRM_FireInternalAutomator('invoice.new',array( - 'id'=>$newID, - 'data'=>$data, - 'againstids'=>$againstIDs, - 'extsource'=>$approvedExternalSource, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); + 'id' => -1, - $data['id'] = $newID; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $this->events_manager->invoice()->created( $data ); - } - - return $newID; + // generic pass-through (array of tag strings or tag IDs): + 'tag_input' => -1, - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); - - #} Failed to Insert - return false; + // or either specific: + 'tagIDs' => -1, + 'tags' => -1, - } + 'mode' => 'append', - } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - return false; + #} ========== CHECK FIELDS ============ - } + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } - /** - * adds or updates a invoice's tags - * ... this is really just a wrapper for addUpdateObjectTags - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateInvoiceTags($args=array()){ + #} ========= / CHECK FIELDS =========== + + return $this->DAL()->addUpdateObjectTags( + array( + 'objtype' => ZBS_TYPE_INVOICE, + 'objid' => $id, + 'tag_input' => $tag_input, + 'tags' => $tags, + 'tagIDs' => $tagIDs, + 'mode' => $mode, + ) + ); + } - global $ZBSCRM_t,$wpdb; + /** + * updates status for an invoice (no blanks allowed) + * + * @param int id Invoice ID + * @param string Invoice Status + * + * @return bool + */ + public function setInvoiceStatus( $id = -1, $status = -1 ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + global $zbs; - 'id' => -1, + $id = (int) $id; + + if ( $id > 0 && ! empty( $status ) && $status !== -1 ) { + + return $this->addUpdateInvoice( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsi_status', + 'val' => $status, + 'type' => '%s', + ), + ), + ) + ); - // generic pass-through (array of tag strings or tag IDs): - 'tag_input' => -1, + } - // or either specific: - 'tagIDs' => -1, - 'tags' => -1, + return false; + } - 'mode' => 'append' + /** + * deletes a invoice object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteInvoice( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'saveOrphans' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - #} ========== CHECK FIELDS ============ + // delete orphans? + if ( $saveOrphans === false ) { - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; + // delete any tag links + $this->DAL()->deleteTagObjLinks( + array( - #} ========= / CHECK FIELDS =========== + 'objtype' => ZBS_TYPE_INVOICE, + 'objid' => $id, + ) + ); - return $this->DAL()->addUpdateObjectTags( - array( - 'objtype' => ZBS_TYPE_INVOICE, - 'objid' => $id, - 'tag_input' => $tag_input, - 'tags' => $tags, - 'tagIDs' => $tagIDs, - 'mode' => $mode - ) - ); + // delete any external source information + $this->DAL()->delete_external_sources( + array( - } + 'obj_type' => ZBS_TYPE_INVOICE, + 'obj_id' => $id, + 'obj_source' => 'all', + ) + ); - /** - * updates status for an invoice (no blanks allowed) - * - * @param int id Invoice ID - * @param string Invoice Status - * - * @return bool - */ - public function setInvoiceStatus($id=-1,$status=-1){ + // delete any links to contacts + $this->DAL()->deleteObjLinks( + array( - global $zbs; + 'objtypefrom' => ZBS_TYPE_INVOICE, + 'objtypeto' => ZBS_TYPE_CONTACT, + 'objtofrom' => $id, - $id = (int)$id; + ) + ); - if ($id > 0 && !empty($status) && $status !== -1){ + // delete any links to transactions + $this->DAL()->deleteObjLinks( + array( - return $this->addUpdateInvoice(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbsi_status','val' => $status,'type' => '%s') - ))); + 'objtypefrom' => ZBS_TYPE_TRANSACTION, + 'objtypeto' => ZBS_TYPE_INVOICE, + 'objtoid' => $id, - } + ) + ); - return false; - - } + // delete all orphaned lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $id, + 'objType' => ZBS_TYPE_INVOICE, + ) + ); + // delete all orphaned line items obj links + $this->DAL()->deleteObjLinks( + array( - /** - * deletes a invoice object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteInvoice($args=array()){ + 'objtypefrom' => ZBS_TYPE_LINEITEM, + 'objtypeto' => ZBS_TYPE_INVOICE, + 'objtoid' => $id, - global $ZBSCRM_t,$wpdb,$zbs; + ) + ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } - 'id' => -1, - 'saveOrphans' => false + $del = zeroBSCRM_db2_deleteGeneric( $id, 'invoices' ); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'invoice.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ + return $del; - // delete any tag links - $this->DAL()->deleteTagObjLinks(array( + } - 'objtype' => ZBS_TYPE_INVOICE, - 'objid' => $id - )); + return false; + } - // delete any external source information - $this->DAL()->delete_external_sources( array( + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array invoice (clean obj) + */ + private function tidy_invoice( $obj = false, $withCustomFields = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = $obj->zbs_owner; + + $res['id_override'] = $this->stripSlashes( $obj->zbsi_id_override ); + $res['parent'] = (int) $obj->zbsi_parent; + $res['status'] = $this->stripSlashes( $obj->zbsi_status ); + $res['status_label'] = __( $res['status'], 'zero-bs-crm' ); // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText + $res['hash'] = $this->stripSlashes( $obj->zbsi_hash ); + $res['pdf_template'] = $this->stripSlashes( $obj->zbsi_pdf_template ); + $res['portal_template'] = $this->stripSlashes( $obj->zbsi_portal_template ); + $res['email_template'] = $this->stripSlashes( $obj->zbsi_email_template ); + $res['invoice_frequency'] = (int) $obj->zbsi_invoice_frequency; + $res['currency'] = $this->stripSlashes( $obj->zbsi_currency ); + $res['pay_via'] = (int) $obj->zbsi_pay_via; + $res['logo_url'] = $this->stripSlashes( $obj->zbsi_logo_url ); + $res['address_to_objtype'] = (int) $obj->zbsi_address_to_objtype; + $res['addressed_from'] = $this->stripSlashes( $obj->zbsi_addressed_from ); + $res['addressed_to'] = $this->stripSlashes( $obj->zbsi_addressed_to ); + $res['allow_partial'] = (bool) $obj->zbsi_allow_partial; + $res['allow_tip'] = (bool) $obj->zbsi_allow_tip; + $res['send_attachments'] = (bool) $obj->zbsi_send_attachments; + $res['hours_or_quantity'] = $this->stripSlashes( $obj->zbsi_hours_or_quantity ); + $res['date'] = (int) $obj->zbsi_date; + $res['date_date'] = ( isset( $obj->zbsi_date ) && $obj->zbsi_date > 0 ) ? jpcrm_uts_to_date_str( $obj->zbsi_date ) : false; + $res['due_date'] = (int) $obj->zbsi_due_date; + $res['due_date_date'] = ( isset( $obj->zbsi_due_date ) && $obj->zbsi_due_date > 0 ) ? jpcrm_uts_to_date_str( $obj->zbsi_due_date ) : false; + $res['paid_date'] = (int) $obj->zbsi_paid_date; + $res['paid_date_date'] = ( isset( $obj->zbsi_paid_date ) && $obj->zbsi_paid_date > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsi_paid_date, false, true ) : false; + $res['hash_viewed'] = (int) $obj->zbsi_hash_viewed; + $res['hash_viewed_date'] = ( isset( $obj->zbsi_hash_viewed ) && $obj->zbsi_hash_viewed > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsi_hash_viewed, false, true ) : false; + $res['hash_viewed_count'] = (int) $obj->zbsi_hash_viewed_count; + $res['portal_viewed'] = (int) $obj->zbsi_portal_viewed; + $res['portal_viewed_date'] = ( isset( $obj->zbsi_portal_viewed ) && $obj->zbsi_portal_viewed > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsi_portal_viewed, false, true ) : false; + $res['portal_viewed_count'] = (int) $obj->zbsi_portal_viewed_count; + $res['net'] = $this->stripSlashes( $obj->zbsi_net ); + $res['discount'] = $this->stripSlashes( $obj->zbsi_discount ); + $res['discount_type'] = $this->stripSlashes( $obj->zbsi_discount_type ); + $res['shipping'] = $this->stripSlashes( $obj->zbsi_shipping ); + $res['shipping_taxes'] = $this->stripSlashes( $obj->zbsi_shipping_taxes ); + $res['shipping_tax'] = $this->stripSlashes( $obj->zbsi_shipping_tax ); + $res['taxes'] = $this->stripSlashes( $obj->zbsi_taxes ); + $res['tax'] = $this->stripSlashes( $obj->zbsi_tax ); + $res['total'] = $this->stripSlashes( $obj->zbsi_total ); + $res['created'] = (int) $obj->zbsi_created; + $res['created_date'] = ( isset( $obj->zbsi_created ) && $obj->zbsi_created > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbsi_created ) : false; + $res['lastupdated'] = (int) $obj->zbsi_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbsi_lastupdated ) && $obj->zbsi_lastupdated > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbsi_lastupdated ) : false; + + // custom fields - tidy any that are present: + if ( $withCustomFields ) { + $res = $this->tidyAddCustomFields( ZBS_TYPE_INVOICE, $obj, $res, false ); + } + } - 'obj_type' => ZBS_TYPE_INVOICE, - 'obj_id' => $id, - 'obj_source' => 'all', - - ) ); - - // delete any links to contacts - $this->DAL()->deleteObjLinks( array( - - 'objtypefrom' => ZBS_TYPE_INVOICE, - 'objtypeto' => ZBS_TYPE_CONTACT, - 'objtofrom' => $id, - - ) ); - - // delete any links to transactions - $this->DAL()->deleteObjLinks( array( - - 'objtypefrom' => ZBS_TYPE_TRANSACTION, - 'objtypeto' => ZBS_TYPE_INVOICE, - 'objtoid' => $id, - - ) ); - - // delete all orphaned lineitems - $this->DAL()->lineitems->deleteLineItemsForObject( array( - 'objID' => $id, - 'objType' => ZBS_TYPE_INVOICE - ) ); - - // delete all orphaned line items obj links - $this->DAL()->deleteObjLinks( array( - - 'objtypefrom' => ZBS_TYPE_LINEITEM, - 'objtypeto' => ZBS_TYPE_INVOICE, - 'objtoid' => $id, - - ) ); - - } - - $del = zeroBSCRM_db2_deleteGeneric($id,'invoices'); - - #} Add to automator - zeroBSCRM_FireInternalAutomator('invoice.delete',array( - 'id'=>$id, - 'saveOrphans'=>$saveOrphans - )); - - return $del; - - } - - return false; - - } - - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array invoice (clean obj) - */ - private function tidy_invoice($obj=false,$withCustomFields=false){ - - $res = false; - - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = $obj->zbs_owner; - - - $res['id_override'] = $this->stripSlashes($obj->zbsi_id_override); - $res['parent'] = (int)$obj->zbsi_parent; - $res['status'] = $this->stripSlashes($obj->zbsi_status); - $res['status_label'] = __( $res['status'], 'zero-bs-crm' ); // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText - $res['hash'] = $this->stripSlashes($obj->zbsi_hash); - $res['pdf_template'] = $this->stripSlashes($obj->zbsi_pdf_template); - $res['portal_template'] = $this->stripSlashes($obj->zbsi_portal_template); - $res['email_template'] = $this->stripSlashes($obj->zbsi_email_template); - $res['invoice_frequency'] = (int)$obj->zbsi_invoice_frequency; - $res['currency'] = $this->stripSlashes($obj->zbsi_currency); - $res['pay_via'] = (int)$obj->zbsi_pay_via; - $res['logo_url'] = $this->stripSlashes($obj->zbsi_logo_url); - $res['address_to_objtype'] = (int)$obj->zbsi_address_to_objtype; - $res['addressed_from'] = $this->stripSlashes($obj->zbsi_addressed_from); - $res['addressed_to'] = $this->stripSlashes($obj->zbsi_addressed_to); - $res['allow_partial'] = (bool)$obj->zbsi_allow_partial; - $res['allow_tip'] = (bool)$obj->zbsi_allow_tip; - $res['send_attachments'] = (bool)$obj->zbsi_send_attachments; - $res['hours_or_quantity'] = $this->stripSlashes($obj->zbsi_hours_or_quantity); - $res['date'] = (int)$obj->zbsi_date; - $res['date_date'] = (isset($obj->zbsi_date) && $obj->zbsi_date > 0) ? jpcrm_uts_to_date_str( $obj->zbsi_date ) : false; - $res['due_date'] = (int)$obj->zbsi_due_date; - $res['due_date_date'] = (isset($obj->zbsi_due_date) && $obj->zbsi_due_date > 0) ? jpcrm_uts_to_date_str( $obj->zbsi_due_date ) : false; - $res['paid_date'] = (int)$obj->zbsi_paid_date; - $res['paid_date_date'] = (isset($obj->zbsi_paid_date) && $obj->zbsi_paid_date > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsi_paid_date,false,true) : false; - $res['hash_viewed'] = (int)$obj->zbsi_hash_viewed; - $res['hash_viewed_date'] = (isset($obj->zbsi_hash_viewed) && $obj->zbsi_hash_viewed > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsi_hash_viewed,false,true) : false; - $res['hash_viewed_count'] = (int)$obj->zbsi_hash_viewed_count; - $res['portal_viewed'] = (int)$obj->zbsi_portal_viewed; - $res['portal_viewed_date'] = (isset($obj->zbsi_portal_viewed) && $obj->zbsi_portal_viewed > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsi_portal_viewed,false,true) : false; - $res['portal_viewed_count'] = (int)$obj->zbsi_portal_viewed_count; - $res['net'] = $this->stripSlashes($obj->zbsi_net); - $res['discount'] = $this->stripSlashes($obj->zbsi_discount); - $res['discount_type'] = $this->stripSlashes($obj->zbsi_discount_type); - $res['shipping'] = $this->stripSlashes($obj->zbsi_shipping); - $res['shipping_taxes'] = $this->stripSlashes($obj->zbsi_shipping_taxes); - $res['shipping_tax'] = $this->stripSlashes($obj->zbsi_shipping_tax); - $res['taxes'] = $this->stripSlashes($obj->zbsi_taxes); - $res['tax'] = $this->stripSlashes($obj->zbsi_tax); - $res['total'] = $this->stripSlashes($obj->zbsi_total); - $res['created'] = (int)$obj->zbsi_created; - $res['created_date'] = (isset($obj->zbsi_created) && $obj->zbsi_created > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsi_created) : false; - $res['lastupdated'] = (int)$obj->zbsi_lastupdated; - $res['lastupdated_date'] = (isset($obj->zbsi_lastupdated) && $obj->zbsi_lastupdated > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsi_lastupdated) : false; - - // custom fields - tidy any that are present: - if ($withCustomFields) $res = $this->tidyAddCustomFields(ZBS_TYPE_INVOICE,$obj,$res,false); - - } - - - return $res; - - - } + return $res; + } /** * Takes whatever invoice data available and re-calculates net, total, tax etc. @@ -2377,312 +2730,313 @@ public function recalculate( $invoice_data = false ) { return false; } - /** - * Takes whatever invoice data available and generates correct totals table (discount, shipping, tax vals) - * - * @param array $invoiceData - * - * @return array $invoiceTotals - */ - public function generateTotalsTable($invoice=false){ - - $totals = array( - - // not req. as part of main obj 'net' - 'discount' => 0.0, - 'taxes' => array(), - // not req. as part of main obj 'shipping' - // not req. as part of main obj 'total' - ); - - // settings - global $zbs; $invsettings = $zbs->settings->getAll(); - - // Discount - if (isset($invoice["discount"]) && !empty($invoice["discount"])) { - - if ($invsettings['invdis'] == 1){ - - // v3.0+ we have discount type ('m' or '%') - $discountType = 'value'; if (isset($invoice["discount_type"]) && !empty($invoice["discount_type"])){ - - if ($invoice["discount_type"] == '%') $discountType = 'percentage'; - - } - - if ($discountType == 'value'){ - - // value out $£ - if (isset($invoice["discount"]) && !empty($invoice["discount"])){ - - $totals['discount'] = $invoice["discount"]; - - } - - } else { - - // percentage out - calc - if (isset($invoice["discount"]) && !empty($invoice["discount"]) && isset($invoice['net'])){ - - $discountAmount = 0; - $invDiscount = (float)$invoice["discount"]; - if ($invDiscount > 0) $discountAmount = ($invDiscount/100)*$invoice['net']; + /** + * Takes whatever invoice data available and generates correct totals table (discount, shipping, tax vals) + * + * @param array $invoiceData + * + * @return array $invoiceTotals + */ + public function generateTotalsTable( $invoice = false ) { - $totals['discount'] = $discountAmount; + $totals = array( - } + // not req. as part of main obj 'net' + 'discount' => 0.0, + 'taxes' => array(), + // not req. as part of main obj 'shipping' + // not req. as part of main obj 'total' + ); - } + // settings + global $zbs; + $invsettings = $zbs->settings->getAll(); - } - } + // Discount + if ( isset( $invoice['discount'] ) && ! empty( $invoice['discount'] ) ) { - if ($invsettings['invtax'] == 1){ - - // this output's tax in 1 number - //if(isset($invoice["tax"]) && !empty($invoice["tax"])){ $totalsTable .= zeroBSCRM_formatCurrency($invoice["tax"]); }else{ $totalsTable .= zeroBSCRM_formatCurrency(0); } - // ... but local taxes need splitting, so recalc & display by lineitems. - $taxLines = false; if (isset($invoice['lineitems']) && is_array($invoice['lineitems']) && count($invoice['lineitems']) > 0){ + if ( $invsettings['invdis'] == 1 ) { - // here we use this summarising func to retrieve - $taxLines = $zbs->DAL->lineitems->getLineitemsTaxSummary(array('lineItems' => $invoice['lineitems'])); + // v3.0+ we have discount type ('m' or '%') + $discountType = 'value'; if ( isset( $invoice['discount_type'] ) && ! empty( $invoice['discount_type'] ) ) { - } + if ( $invoice['discount_type'] == '%' ) { + $discountType = 'percentage'; + } + } - // add any shipping tax :) - if ($invsettings['invpandp'] == 1){ + if ( $discountType == 'value' ) { - // shipping (if used) - $shippingV = 0.0; $taxOnShipping = 0.0; + // value out $£ + if ( isset( $invoice['discount'] ) && ! empty( $invoice['discount'] ) ) { - // shipping subtotal - if (isset($invoice["shipping"]) && !empty($invoice["shipping"])){ + $totals['discount'] = $invoice['discount']; - $shippingV = (float)$invoice["shipping"]; + } + } else { - } + // percentage out - calc + if ( isset( $invoice['discount'] ) && ! empty( $invoice['discount'] ) && isset( $invoice['net'] ) ) { - if ($shippingV > 0){ + $discountAmount = 0; + $invDiscount = (float) $invoice['discount']; + if ( $invDiscount > 0 ) { + $discountAmount = ( $invDiscount / 100 ) * $invoice['net']; + } - // tax on shipping - recalc. - if (isset($invoice['shipping_taxes'])) $taxOnShipping = zeroBSCRM_taxRates_getTaxValue($shippingV,$invoice['shipping_taxes']); + $totals['discount'] = $discountAmount; - // shipping can only have 1 tax at the moment, so find that tax and add to summary: - $shippingRate = zeroBSCRM_taxRates_getTaxRate($invoice['shipping_taxes']); + } + } + } + } - if (is_array($shippingRate) && isset($shippingRate['id'])){ + if ( $invsettings['invtax'] == 1 ) { - // add to summary - if (!isset($taxLines[$shippingRate['id']])){ + // this output's tax in 1 number + // if(isset($invoice["tax"]) && !empty($invoice["tax"])){ $totalsTable .= zeroBSCRM_formatCurrency($invoice["tax"]); }else{ $totalsTable .= zeroBSCRM_formatCurrency(0); } + // ... but local taxes need splitting, so recalc & display by lineitems. + $taxLines = false; if ( isset( $invoice['lineitems'] ) && is_array( $invoice['lineitems'] ) && count( $invoice['lineitems'] ) > 0 ) { - // new, add - $taxLines[$shippingRate['id']] = array( + // here we use this summarising func to retrieve + $taxLines = $zbs->DAL->lineitems->getLineitemsTaxSummary( array( 'lineItems' => $invoice['lineitems'] ) ); - 'name' => $shippingRate['name'], - 'rate' => $shippingRate['rate'], - 'value' => $taxOnShipping + } - ); + // add any shipping tax :) + if ( $invsettings['invpandp'] == 1 ) { - } else { + // shipping (if used) + $shippingV = 0.0; + $taxOnShipping = 0.0; - // += - $taxLines[$shippingRate['id']]['value'] += $taxOnShipping; + // shipping subtotal + if ( isset( $invoice['shipping'] ) && ! empty( $invoice['shipping'] ) ) { - } + $shippingV = (float) $invoice['shipping']; - } + } - } + if ( $shippingV > 0 ) { - } + // tax on shipping - recalc. + if ( isset( $invoice['shipping_taxes'] ) ) { + $taxOnShipping = zeroBSCRM_taxRates_getTaxValue( $shippingV, $invoice['shipping_taxes'] ); + } - if (isset($taxLines) && is_array($taxLines) && count($taxLines) > 0) { + // shipping can only have 1 tax at the moment, so find that tax and add to summary: + $shippingRate = zeroBSCRM_taxRates_getTaxRate( $invoice['shipping_taxes'] ); - $totals['taxes'] = $taxLines; + if ( is_array( $shippingRate ) && isset( $shippingRate['id'] ) ) { - } else { + // add to summary + if ( ! isset( $taxLines[ $shippingRate['id'] ] ) ) { - // simple fallback - // ...just use $invoice["tax"] + // new, add + $taxLines[ $shippingRate['id'] ] = array( - } + 'name' => $shippingRate['name'], + 'rate' => $shippingRate['rate'], + 'value' => $taxOnShipping, - } + ); - return $totals; + } else { - } + // += + $taxLines[ $shippingRate['id'] ]['value'] += $taxOnShipping; + } + } + } + } + if ( isset( $taxLines ) && is_array( $taxLines ) && count( $taxLines ) > 0 ) { - /** - * Wrapper, use $this->getInvoiceMeta($contactID,$key) for easy retrieval of singular invoice - * Simplifies $this->getMeta - * - * @param int objtype - * @param int objid - * @param string key - * - * @return array invoice meta result - */ - public function getInvoiceMeta($id=-1,$key='',$default=false){ + $totals['taxes'] = $taxLines; - global $zbs; + } else { - if (!empty($key)){ + // simple fallback + // ...just use $invoice["tax"] - return $this->DAL()->getMeta(array( + } + } - 'objtype' => ZBS_TYPE_INVOICE, - 'objid' => $id, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default, - 'ignoreowner' => true // for now !! + return $totals; + } - )); + /** + * Wrapper, use $this->getInvoiceMeta($contactID,$key) for easy retrieval of singular invoice + * Simplifies $this->getMeta + * + * @param int objtype + * @param int objid + * @param string key + * + * @return array invoice meta result + */ + public function getInvoiceMeta( $id = -1, $key = '', $default = false ) { - } + global $zbs; - return $default; - } + if ( ! empty( $key ) ) { + return $this->DAL()->getMeta( + array( - - /** - * Returns an ownerid against a invoice - * - * @param int id invoice ID - * - * @return int invoice owner id - */ - public function getInvoiceOwner($id=-1){ + 'objtype' => ZBS_TYPE_INVOICE, + 'objid' => $id, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, + 'ignoreowner' => true, // for now !! - global $zbs; + ) + ); - $id = (int)$id; + } - if ($id > 0){ + return $default; + } - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_INVOICE, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); + /** + * Returns an ownerid against a invoice + * + * @param int id invoice ID + * + * @return int invoice owner id + */ + public function getInvoiceOwner( $id = -1 ) { - } + global $zbs; - return false; - - } + $id = (int) $id; - /** - * Returns the first contact associated with an invoice - * - * @param int id quote ID - * - * @return int quote invoice id - */ - public function getInvoiceContactID($id=-1){ + if ( $id > 0 ) { - global $zbs; + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_INVOICE, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); - $id = (int)$id; + } - if ($id > 0){ + return false; + } - $contacts = $this->DAL()->getObjsLinkedToObj(array( + /** + * Returns the first contact associated with an invoice + * + * @param int id quote ID + * + * @return int quote invoice id + */ + public function getInvoiceContactID( $id = -1 ) { - 'objtypefrom' => ZBS_TYPE_INVOICE, - 'objtypeto' => ZBS_TYPE_CONTACT, - 'objfromid' => $id, - 'count' => false, + global $zbs; - )); + $id = (int) $id; - if (is_array($contacts)) foreach ($contacts as $c){ + if ( $id > 0 ) { - // first - return $c['id']; + $contacts = $this->DAL()->getObjsLinkedToObj( + array( - } + 'objtypefrom' => ZBS_TYPE_INVOICE, + 'objtypeto' => ZBS_TYPE_CONTACT, + 'objfromid' => $id, + 'count' => false, - } + ) + ); - return false; - - } + if ( is_array( $contacts ) ) { + foreach ( $contacts as $c ) { + // first + return $c['id']; - - /** - * Returns a contact obj assigned to this invoice - * - * @param int id invoice ID - * - * @return int invoice owner id - */ - public function getInvoiceContact($id=-1){ + } + } + } - global $zbs; + return false; + } - $id = (int)$id; + /** + * Returns a contact obj assigned to this invoice + * + * @param int id invoice ID + * + * @return int invoice owner id + */ + public function getInvoiceContact( $id = -1 ) { - if ($id > 0){ + global $zbs; - $contacts = $this->DAL()->contacts->getContacts(array( + $id = (int) $id; - // link - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, + if ( $id > 0 ) { - // query bits - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + $contacts = $this->DAL()->contacts->getContacts( + array( - if (is_array($contacts) && isset($contacts[0])) return $contacts[0]; - + // link + 'hasObjTypeLinkedTo' => ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo' => $resDataLine->ID, - } + // query bits + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); - return false; - - } - - /** - * Returns a company obj assigned to this invoice - * - * @param int id invoice ID - * - * @return int invoice owner id - */ - public function getInvoiceCompany($id=-1){ + if ( is_array( $contacts ) && isset( $contacts[0] ) ) { + return $contacts[0]; + } + } - global $zbs; + return false; + } - $id = (int)$id; + /** + * Returns a company obj assigned to this invoice + * + * @param int id invoice ID + * + * @return int invoice owner id + */ + public function getInvoiceCompany( $id = -1 ) { - if ($id > 0){ + global $zbs; - $companies = $this->DAL()->companies->getCompanies(array( + $id = (int) $id; - 'hasObjTypeLinkedTo' => ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo' => $resDataLine->ID, + if ( $id > 0 ) { - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY)) - ); + $companies = $this->DAL()->companies->getCompanies( + array( - if (is_array($companies) && isset($companies[0])) return $companies[0]; - + 'hasObjTypeLinkedTo' => ZBS_TYPE_INVOICE, + 'hasObjIDLinkedTo' => $resDataLine->ID, - } + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); - return false; - - } + if ( is_array( $companies ) && isset( $companies[0] ) ) { + return $companies[0]; + } + } + return false; + } /** * Returns an status against a invoice @@ -2691,25 +3045,27 @@ public function getInvoiceCompany($id=-1){ * * @return string invoice status string */ - public function getInvoiceStatus($id=-1){ + public function getInvoiceStatus( $id = -1 ) { - global $zbs; + global $zbs; - $id = (int)$id; + $id = (int) $id; - if ($id > 0){ + if ( $id > 0 ) { - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_INVOICE, - 'colname' => 'zbsi_status', - 'ignoreowner'=>true)); + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_INVOICE, + 'colname' => 'zbsi_status', + 'ignoreowner' => true, + ) + ); - } + } - return false; - - } + return false; + } /** * Returns an SQL query addition which will allow filtering of invoices @@ -2736,26 +3092,27 @@ public function get_invoice_status_except_deleted_for_query( $table_alias_sql = * * @return string invoice hash string */ - public function getInvoiceHash($id=-1){ + public function getInvoiceHash( $id = -1 ) { - global $zbs; - - $id = (int)$id; + global $zbs; - if ($id > 0){ + $id = (int) $id; - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_INVOICE, - 'colname' => 'zbsi_hash', - 'ignoreowner'=>true)); + if ( $id > 0 ) { - } + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_INVOICE, + 'colname' => 'zbsi_hash', + 'ignoreowner' => true, + ) + ); - return false; - - } + } + return false; + } /** * Retrieves outstanding balanace against an invoice, based on transactions assigned to it. @@ -2764,148 +3121,151 @@ public function getInvoiceHash($id=-1){ * * @return float invoice outstanding balance */ - public function getOutstandingBalance($invoiceID=-1){ + public function getOutstandingBalance( $invoiceID = -1 ) { - if ($invoiceID > 0){ + if ( $invoiceID > 0 ) { - $invoice = $this->getInvoice($invoiceID,array( + $invoice = $this->getInvoice( + $invoiceID, + array( - 'withTransactions' => true // so we can see other partials and check if paid. + 'withTransactions' => true, // so we can see other partials and check if paid. - )); + ) + ); - if (is_array($invoice)){ + if ( is_array( $invoice ) ) { - // get total due + // get total due $invoice_total_value = 0.0; - if ( isset( $invoice['total'] ) ) { - $invoice_total_value = (float) $invoice['total']; - // this one'll be a rolling sum - $transactions_total_value = 0.0; - - // cycle through trans + calc existing balance - if ( isset( $invoice['transactions'] ) && is_array( $invoice['transactions'] ) ) { - - // got trans - foreach ( $invoice['transactions'] as $transaction ) { + if ( isset( $invoice['total'] ) ) { + $invoice_total_value = (float) $invoice['total']; + // this one'll be a rolling sum + $transactions_total_value = 0.0; - // should we also check for status=completed/succeeded? (leaving for now, will let check all): + // cycle through trans + calc existing balance + if ( isset( $invoice['transactions'] ) && is_array( $invoice['transactions'] ) ) { - // get amount - $transaction_amount = 0.0; + // got trans + foreach ( $invoice['transactions'] as $transaction ) { - if ( isset( $transaction['total'] ) ) { - $transaction_amount = (float) $transaction['total']; + // should we also check for status=completed/succeeded? (leaving for now, will let check all): - if ( $transaction_amount > 0 ) { + // get amount + $transaction_amount = 0.0; - switch ( $transaction['type'] ) { - case __( 'Sale', 'zero-bs-crm' ): - // these count as debits against invoice. - $transactions_total_value -= $transaction_amount; + if ( isset( $transaction['total'] ) ) { + $transaction_amount = (float) $transaction['total']; - break; + if ( $transaction_amount > 0 ) { - case __( 'Refund', 'zero-bs-crm' ): - case __( 'Credit Note', 'zero-bs-crm' ): - // these count as credits against invoice. - $transactions_total_value += $transaction_amount; + switch ( $transaction['type'] ) { + case __( 'Sale', 'zero-bs-crm' ): + // these count as debits against invoice. + $transactions_total_value -= $transaction_amount; - break; + break; - } // / switch on type (sale/refund) + case __( 'Refund', 'zero-bs-crm' ): + case __( 'Credit Note', 'zero-bs-crm' ): + // these count as credits against invoice. + $transactions_total_value += $transaction_amount; - } // / if trans > 0 + break; - } // / if isset + } // / switch on type (sale/refund) - } // / each trans + } // / if trans > 0 - // should now have $transactions_total_value & $invoice_total_value - // ... so we sum + return. - return $invoice_total_value + $transactions_total_value; + } // / if isset - } // / if has trans - } // if isset invoice total + } // / each trans - } // / if retrieved inv + // should now have $transactions_total_value & $invoice_total_value + // ... so we sum + return. + return $invoice_total_value + $transactions_total_value; - } // / if invoice_id > 0 + } // / if has trans + } // if isset invoice total - return false; + } // / if retrieved inv - } - - - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * This does so based on the objectModel! - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - private function db_ready_invoice($obj=false){ - - // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); - - } + } // / if invoice_id > 0 + return false; + } + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * This does so based on the objectModel! + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + private function db_ready_invoice( $obj = false ) { - /** - * Takes full object and makes a "list view" boiled down version - * Used to generate listview objs - * - * @param array $obj (clean obj) - * - * @return array (listview ready obj) - */ - public function listViewObj($invoice=false,$columnsRequired=array()){ + // use the generic? (override here if necessary) + return $this->db_ready_obj( $obj ); + } - if (is_array($invoice) && isset($invoice['id'])){ + /** + * Takes full object and makes a "list view" boiled down version + * Used to generate listview objs + * + * @param array $obj (clean obj) + * + * @return array (listview ready obj) + */ + public function listViewObj( $invoice = false, $columnsRequired = array() ) { - $resArr = $invoice; + if ( is_array( $invoice ) && isset( $invoice['id'] ) ) { - // a lot of this is legacy > LineItems -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> LineItems + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_lineitems extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_LINEITEM; - protected $objectDBPrefix = 'zbsli_'; - protected $objectModel = array( - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'order' => array('fieldname' => 'zbsli_order', 'format' => 'int'), - 'title' => array( - 'fieldname' => 'zbsli_title', - 'format' => 'str', - 'max_len' => 300 - ), - 'desc' => array( - 'fieldname' => 'zbsli_desc', - 'format' => 'str', - 'max_len' => 300 - ), - 'quantity' => array('fieldname' => 'zbsli_quantity', 'format' => 'decimal'), - 'price' => array('fieldname' => 'zbsli_price', 'format' => 'decimal'), - 'currency' => array('fieldname' => 'zbsli_currency', 'format' => 'curr'), - 'net' => array('fieldname' => 'zbsli_net', 'format' => 'decimal'), - 'discount' => array('fieldname' => 'zbsli_discount', 'format' => 'decimal'), - 'fee' => array('fieldname' => 'zbsli_fee', 'format' => 'decimal'), - 'shipping' => array('fieldname' => 'zbsli_shipping', 'format' => 'decimal'), - 'shipping_taxes' => array('fieldname' => 'zbsli_shipping_taxes', 'format' => 'str'), - 'shipping_tax' => array('fieldname' => 'zbsli_shipping_tax', 'format' => 'decimal'), - 'taxes' => array('fieldname' => 'zbsli_taxes', 'format' => 'str'), - 'tax' => array('fieldname' => 'zbsli_tax', 'format' => 'decimal'), - 'total' => array('fieldname' => 'zbsli_total', 'format' => 'decimal'), - 'created' => array('fieldname' => 'zbsli_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsli_lastupdated', 'format' => 'uts'), - - ); - - - function __construct($args=array()) { - - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - - } - - // =============================================================================== - // =========== LINEITEM ======================================================= - - /** - * returns full lineitem line +- details - * - * @param int id lineitem id - * @param array $args Associative array of arguments - * - * @return array lineitem object - */ - public function getLineitem($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - // permissions - 'ignoreowner' => false, // this'll let you not-check the owner of obj - - // returns scalar ID of line - 'onlyID' => false, - - 'fields' => false // false = *, array = fieldnames - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check ID - $id = (int)$id; - if ( - (!empty($id) && $id > 0) - || - (!empty($email)) - || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ - - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; - - - #} ============= PRE-QUERY ============ - - - $selector = 'lineitem.*'; - if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $selector = ''; - - // always needs id, so add if not present - if (!in_array('ID',$fields)) $selector = 'lineitem.ID'; - - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'lineitem.'.$f; - } - } else if ($onlyID){ - $selector = 'lineitem.ID'; - } - - #} ============ / PRE-QUERY =========== - - - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['lineitems'].' as lineitem'; - #} ============= WHERE ================ - - if (!empty($id) && $id > 0){ - - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); - - } - - - #} ============ / WHERE ============== - - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE - - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); - - try { - - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $this->catchSQLError($e); - - } - - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { - - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID) return $potentialRes->ID; - - // tidy - if (is_array($fields)){ - // guesses fields based on table col names - $res = $this->lazyTidyGeneric($potentialRes); - } else { - // proper tidy - $res = $this->tidy_lineitem($potentialRes,$withCustomFields); - } - - return $res; - - } - - } // / if ID + protected $objectType = ZBS_TYPE_LINEITEM; + protected $objectDBPrefix = 'zbsli_'; + protected $objectModel = array( + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'order' => array( + 'fieldname' => 'zbsli_order', + 'format' => 'int', + ), + 'title' => array( + 'fieldname' => 'zbsli_title', + 'format' => 'str', + 'max_len' => 300, + ), + 'desc' => array( + 'fieldname' => 'zbsli_desc', + 'format' => 'str', + 'max_len' => 300, + ), + 'quantity' => array( + 'fieldname' => 'zbsli_quantity', + 'format' => 'decimal', + ), + 'price' => array( + 'fieldname' => 'zbsli_price', + 'format' => 'decimal', + ), + 'currency' => array( + 'fieldname' => 'zbsli_currency', + 'format' => 'curr', + ), + 'net' => array( + 'fieldname' => 'zbsli_net', + 'format' => 'decimal', + ), + 'discount' => array( + 'fieldname' => 'zbsli_discount', + 'format' => 'decimal', + ), + 'fee' => array( + 'fieldname' => 'zbsli_fee', + 'format' => 'decimal', + ), + 'shipping' => array( + 'fieldname' => 'zbsli_shipping', + 'format' => 'decimal', + ), + 'shipping_taxes' => array( + 'fieldname' => 'zbsli_shipping_taxes', + 'format' => 'str', + ), + 'shipping_tax' => array( + 'fieldname' => 'zbsli_shipping_tax', + 'format' => 'decimal', + ), + 'taxes' => array( + 'fieldname' => 'zbsli_taxes', + 'format' => 'str', + ), + 'tax' => array( + 'fieldname' => 'zbsli_tax', + 'format' => 'decimal', + ), + 'total' => array( + 'fieldname' => 'zbsli_total', + 'format' => 'decimal', + ), + 'created' => array( + 'fieldname' => 'zbsli_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsli_lastupdated', + 'format' => 'uts', + ), + + ); + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + } - return false; + // =============================================================================== + // =========== LINEITEM ======================================================= - } + /** + * returns full lineitem line +- details + * + * @param int id lineitem id + * @param array $args Associative array of arguments + * + * @return array lineitem object + */ + public function getLineitem( $id = -1, $args = array() ) { + + global $zbs; + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // permissions + 'ignoreowner' => false, // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + 'fields' => false, // false = *, array = fieldnames + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + #} Check ID + $id = (int) $id; + if ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $email ) ) + || + ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) + ) { + + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $extraSelect = ''; + + #} ============= PRE-QUERY ============ + + $selector = 'lineitem.*'; + if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $selector = ''; - /** - * returns lineitem detail lines - * - * @param array $args Associative array of arguments - * - * @return array of lineitem lines - */ - public function getLineitems($args=array()){ + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'lineitem.ID'; + } - global $zbs; + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'lineitem.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'lineitem.ID'; + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ / PRE-QUERY =========== - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches zbsli_title, zbsli_desc - 'associatedObjType' => false, // e.g. ZBS_TYPE_QUOTE - 'associatedObjID' => false, // e.g. 123 - // Note on associated types: They can be used: - // associatedObjType - // associatedObjType + associatedObjID - // BUT NOT JUST associatedObjID (would bring collisions) + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['lineitems'] . ' as lineitem'; + #} ============= WHERE ================ - 'withCustomFields' => false, // none yet anyhow + if ( ! empty( $id ) && $id > 0 ) { - // returns - 'count' => false, + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 100, - 'whereCase' => 'AND', // DEFAULT = AND + } - // permissions - 'ignoreowner' => false, // this'll let you not-check the owner of obj + #} ============ / WHERE ============== + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - global $ZBSCRM_t,$wpdb,$zbs; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - #} ============= PRE-QUERY ============ + try { - #} Capitalise this - $sortOrder = strtoupper($sortOrder); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - #} If just count, turn off any extra gumpf - //if ($count) { } + } catch ( Exception $e ) { - #} ============ / PRE-QUERY =========== + #} General SQL Err + $this->catchSQLError( $e ); - #} Build query - $query = "SELECT lineitem.*".$extraSelect." FROM ".$ZBSCRM_t['lineitems'].' as lineitem'.$joinQ; + } - #} Count override - if ($count) $query = "SELECT COUNT(lineitem.ID) FROM ".$ZBSCRM_t['lineitems'].' as lineitem'.$joinQ; + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - #} ============= WHERE ================ + #} Has results, tidy + return - #} Add Search phrase - if (!empty($searchPhrase)){ + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } - // search? - ALL THESE COLS should probs have index of FULLTEXT in db? - $searchWheres = array(); - $searchWheres['search_title'] = array('zbsli_title','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_desc'] = array('zbsli_desc','LIKE','%s','%'.$searchPhrase.'%'); + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_lineitem( $potentialRes, $withCustomFields ); + } - // This generates a query like 'zbsli_fname LIKE %s OR zbsli_lname LIKE %s', - // which we then need to include as direct subquery (below) in main query :) - $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - - if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ + return $res; - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + } + } // / if ID - } + return false; + } - } + /** + * returns lineitem detail lines + * + * @param array $args Associative array of arguments + * + * @return array of lineitem lines + */ + public function getLineitems( $args = array() ) { + + global $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => '', // searches zbsli_title, zbsli_desc + 'associatedObjType' => false, // e.g. ZBS_TYPE_QUOTE + 'associatedObjID' => false, // e.g. 123 + // Note on associated types: They can be used: + // associatedObjType + // associatedObjType + associatedObjID + // BUT NOT JUST associatedObjID (would bring collisions) + + 'withCustomFields' => false, // none yet anyhow + + // returns + 'count' => false, + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 100, + 'whereCase' => 'AND', // DEFAULT = AND + + // permissions + 'ignoreowner' => false, // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // associated object search - // simplifiers - $hasObjType = false; $hasObjID = false; - if (!empty($associatedObjType) && $associatedObjType > 0) $hasObjType = true; - if (!empty($associatedObjID) && $associatedObjID > 0) $hasObjID = true; + global $ZBSCRM_t, $wpdb, $zbs; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; - // switch depending on setup - if ($hasObjType && $hasObjID){ + #} ============= PRE-QUERY ============ - // has id + type to match to (e.g. quote 123) - $wheres['associatedObjType'] = array('ID','IN','(SELECT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_LINEITEM." AND zbsol_objtype_to = %d AND zbsol_objid_to = %d)",array($associatedObjType,$associatedObjID)); + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); - } else if ($hasObjType && !$hasObjID){ + #} If just count, turn off any extra gumpf + // if ($count) { } - // has type but no id - // e.g. line items attached to invoices - $wheres['associatedObjType'] = array('ID','IN','(SELECT zbsol_objid_from FROM '.$ZBSCRM_t['objlinks']." WHERE zbsol_objtype_from = ".ZBS_TYPE_LINEITEM." AND zbsol_objtype_to = %d)",$associatedObjType); + #} ============ / PRE-QUERY =========== + #} Build query + $query = 'SELECT lineitem.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['lineitems'] . ' as lineitem' . $joinQ; - } else if ($hasObjID && !$hasObjType){ + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(lineitem.ID) FROM ' . $ZBSCRM_t['lineitems'] . ' as lineitem' . $joinQ; + } - // has id but no type - // DO NOTHING, this is dodgy to ever call :) as collision of objs - } + #} ============= WHERE ================ - #} ============ / WHERE =============== + #} Add Search phrase + if ( ! empty( $searchPhrase ) ) { - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; + // search? - ALL THESE COLS should probs have index of FULLTEXT in db? + $searchWheres = array(); + $searchWheres['search_title'] = array( 'zbsli_title', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_desc'] = array( 'zbsli_desc', 'LIKE', '%s', '%' . $searchPhrase . '%' ); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + // This generates a query like 'zbsli_fname LIKE %s OR zbsli_lname LIKE %s', + // which we then need to include as direct subquery (below) in main query :) + $searchQueryArr = $this->buildWheres( $searchWheres, '', array(), 'OR', false ); - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'contact'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + if ( is_array( $searchQueryArr ) && isset( $searchQueryArr['where'] ) && ! empty( $searchQueryArr['where'] ) ) { - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); + // add it + $wheres['direct'][] = array( '(' . $searchQueryArr['where'] . ')', $searchQueryArr['params'] ); - try { + } + } - #} Prep & run query - $queryObj = $this->prepare($query,$params); + // associated object search + // simplifiers + $hasObjType = false; + $hasObjID = false; + if ( ! empty( $associatedObjType ) && $associatedObjType > 0 ) { + $hasObjType = true; + } + if ( ! empty( $associatedObjID ) && $associatedObjID > 0 ) { + $hasObjID = true; + } - #} Catch count + return if requested - if ($count) return $wpdb->get_var($queryObj); + // switch depending on setup + if ( $hasObjType && $hasObjID ) { - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + // has id + type to match to (e.g. quote 123) + $wheres['associatedObjType'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_LINEITEM . ' AND zbsol_objtype_to = %d AND zbsol_objid_to = %d)', array( $associatedObjType, $associatedObjID ) ); - } catch (Exception $e){ + } elseif ( $hasObjType && ! $hasObjID ) { - #} General SQL Err - $this->catchSQLError($e); + // has type but no id + // e.g. line items attached to invoices + $wheres['associatedObjType'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_LINEITEM . ' AND zbsol_objtype_to = %d)', $associatedObjType ); - } + } elseif ( $hasObjID && ! $hasObjType ) { - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + // has id but no type + // DO NOTHING, this is dodgy to ever call :) as collision of objs + } - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $resArr = $this->tidy_lineitem($resDataLine,$withCustomFields); + #} ============ / WHERE =============== - $res[] = $resArr; + #} CHECK this + reset to default if faulty + if ( ! in_array( $whereCase, array( 'AND', 'OR' ) ) ) { + $whereCase = 'AND'; + } - } - } + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params, $whereCase ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'contact' ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - return $res; - } + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); + try { - /** - * Returns a count of lineitems (owned) - * .. inc by status - * - * @return int count - */ - public function getLineItemCount($args=array()){ + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} Catch count + return if requested + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } - // Search/Filtering (leave as false to ignore) + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj + } catch ( Exception $e ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} General SQL Err + $this->catchSQLError( $e ); - $whereArr = array(); + } - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_LINEITEM, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - } + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - /** - * returns tax summary array, of taxes applicable to given lineitems - * - * @param array $args Associative array of arguments - * - * @return array summary of taxes (e.g. array(array('name' => 'VAT','rate' => 20, 'value' => 123.44))) - */ - public function getLineitemsTaxSummary($args=array()){ + // tidy + $resArr = $this->tidy_lineitem( $resDataLine, $withCustomFields ); - global $zbs; + $res[] = $resArr; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } + } - // pass lineitems objs in array - 'lineItems' => array() + return $res; + } + /** + * Returns a count of lineitems (owned) + * .. inc by status + * + * @return int count + */ + public function getLineItemCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + + // permissions + 'ignoreowner' => true, // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + $whereArr = array(); + + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_LINEITEM, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + /** + * returns tax summary array, of taxes applicable to given lineitems + * + * @param array $args Associative array of arguments + * + * @return array summary of taxes (e.g. array(array('name' => 'VAT','rate' => 20, 'value' => 123.44))) + */ + public function getLineitemsTaxSummary( $args = array() ) { + + global $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // pass lineitems objs in array + 'lineItems' => array(), + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - $summaryData = array(); + $summaryData = array(); - // calc + // calc if ( is_array( $lineItems ) && count( $lineItems ) > 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $lineItemTaxes = array(); - $taxRateTable = zeroBSCRM_taxRates_getTaxTableArr(true); - - foreach ($lineItems as $lineItem){ - - // got any taxes on ? - if (isset($lineItem['net']) && isset($lineItem['taxes'])){ - - $taxRatesToApply = array(); - - // get any taxes... - if (strpos($lineItem['taxes'],',')){ - - $taxRateIDs = explode(',', $lineItem['taxes']); - if (is_array($taxRateIDs)) $taxRatesToApply = $taxRateIDs; - - } else $taxRatesToApply[] = (int)$lineItem['taxes']; - - // calc these ones + add to summary - if (is_array($taxRatesToApply)) foreach ($taxRatesToApply as $taxRateID){ - - $rateID = (int)$taxRateID; - if (isset($taxRateTable[$rateID])){ - - // get rate - $rate = 0.0; if (isset($taxRateTable[$rateID]['rate'])) $rate = (float)$taxRateTable[$rateID]['rate']; + $lineItemTaxes = array(); + $taxRateTable = zeroBSCRM_taxRates_getTaxTableArr( true ); - // calc + add - $itemNet = $lineItem['net']; - if (isset($lineItem['discount'])) $itemNet -= $lineItem['discount']; - $taxValue = round($itemNet*($rate/100),2); + foreach ( $lineItems as $lineItem ) { - // add to summary - if (!isset($summaryData[$rateID])){ + // got any taxes on ? + if ( isset( $lineItem['net'] ) && isset( $lineItem['taxes'] ) ) { - // new, add - $summaryData[$rateID] = array( + $taxRatesToApply = array(); - 'name' => $taxRateTable[$rateID]['name'], - 'rate' => $rate, - 'value' => $taxValue + // get any taxes... + if ( strpos( $lineItem['taxes'], ',' ) ) { - ); - - } else { - - // += - $summaryData[$rateID]['value'] += $taxValue; - - } - - } // else not set? - - } // / foreach tax rate to apply - - } // / if has net and taxes - - } // / foreach line item - - } // / if has items + $taxRateIDs = explode( ',', $lineItem['taxes'] ); + if ( is_array( $taxRateIDs ) ) { + $taxRatesToApply = $taxRateIDs; + } + } else { + $taxRatesToApply[] = (int) $lineItem['taxes']; + } - return $summaryData; + // calc these ones + add to summary + if ( is_array( $taxRatesToApply ) ) { + foreach ( $taxRatesToApply as $taxRateID ) { - } + $rateID = (int) $taxRateID; + if ( isset( $taxRateTable[ $rateID ] ) ) { - /** - * adds or updates a lineitem object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateLineitem($args=array()){ + // get rate + $rate = 0.0; + if ( isset( $taxRateTable[ $rateID ]['rate'] ) ) { + $rate = (float) $taxRateTable[ $rateID ]['rate']; + } - global $ZBSCRM_t,$wpdb,$zbs; + // calc + add + $itemNet = $lineItem['net']; + if ( isset( $lineItem['discount'] ) ) { + $itemNet -= $lineItem['discount']; + } + $taxValue = round( $itemNet * ( $rate / 100 ), 2 ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // add to summary + if ( ! isset( $summaryData[ $rateID ] ) ) { - 'id' => -1, - 'owner' => -1, + // new, add + $summaryData[ $rateID ] = array( - // assign to - 'linkedObjType' => -1, - 'linkedObjID' => -1, + 'name' => $taxRateTable[ $rateID ]['name'], + 'rate' => $rate, + 'value' => $taxValue, - // fields (directly) - 'data' => array( + ); - - 'order' => '', - 'title' => '', - 'desc' => '', - 'quantity' => '', - 'price' => '', - 'currency' => '', - 'net' => '', - 'discount' => '', - 'fee' => '', - 'shipping' => '', - 'shipping_taxes' => '', - 'shipping_tax' => '', - 'taxes' => '', - 'tax' => '', - 'total' => '', - 'lastupdated' => '', + } else { - // allow this to be set for sync etc. - 'created' => -1, + // += + $summaryData[ $rateID ]['value'] += $taxValue; - ), + } + } // else not set? - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) - // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + } // / foreach tax rate to apply + } + } // / if has net and taxes - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newLineitem (because is migrating, not creating new :) this was -1 before + } // / foreach line item - 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + } // / if has items - 'calculate_totals' => false // This allows us to recalculate tax, subtotal, total via php (e.g. if added via api). Only works if not using limitedFields + return $summaryData; + } + /** + * adds or updates a lineitem object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateLineitem( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'owner' => -1, + + // assign to + 'linkedObjType' => -1, + 'linkedObjID' => -1, + + // fields (directly) + 'data' => array( + + 'order' => '', + 'title' => '', + 'desc' => '', + 'quantity' => '', + 'price' => '', + 'currency' => '', + 'net' => '', + 'discount' => '', + 'fee' => '', + 'shipping' => '', + 'shipping_taxes' => '', + 'shipping_tax' => '', + 'taxes' => '', + 'tax' => '', + 'total' => '', + 'lastupdated' => '', + + // allow this to be set for sync etc. + 'created' => -1, + + ), + + 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newLineitem (because is migrating, not creating new :) this was -1 before + + 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + + 'calculate_totals' => false, // This allows us to recalculate tax, subtotal, total via php (e.g. if added via api). Only works if not using limitedFields + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - - #} =========== / LOAD ARGS ============ + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ - - $id = (int)$id; - - // here we check that the potential owner CAN even own - if ($owner > 0 && !user_can($owner,'admin_zerobs_usr')) $owner = -1; + #} ========== CHECK FIELDS ============ - // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } + $id = (int) $id; + // here we check that the potential owner CAN even own + if ( $owner > 0 && ! user_can( $owner, 'admin_zerobs_usr' ) ) { + $owner = -1; + } - if (is_array($limitedFields)){ + // if owner = -1, add current + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); } - // LIMITED UPDATE (only a few fields.) - if (!is_array($limitedFields) || count ($limitedFields) <= 0) return false; - // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; + if ( is_array( $limitedFields ) ) { - } else { + // LIMITED UPDATE (only a few fields.) + if ( ! is_array( $limitedFields ) || count( $limitedFields ) <= 0 ) { + return false; + } + // REQ. ID too (can only update) + if ( empty( $id ) || $id <= 0 ) { + return false; + } + } else { - // NORMAL, FULL UPDATE + // NORMAL, FULL UPDATE - // (re)calculate the totals etc? + // (re)calculate the totals etc? if ( $calculate_totals ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $data = $this->recalculate($data); - - } - - } - - #} ========= / CHECK FIELDS =========== - + $data = $this->recalculate( $data ); - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - - // either ext source + setting, or set by the func call - if ($do_not_update_blanks){ - - // this setting says 'don't override filled-out data with blanks' - // so here we check through any passed blanks + convert to limitedFields - // only matters if $id is set (there is somt to update not add - if (isset($id) && !empty($id) && $id > 0){ - - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_lineitem($data); - //unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue - //unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - - $origData = $data; //$data = array(); - $limitedData = array(); // array(array('key'=>'zbsli_x','val'=>y,'type'=>'%s')) - - // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) - // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates - foreach ($dbData as $k => $v){ - - $intV = (int)$v; - - // only add if valuenot empty - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ - - // add to update arr - $limitedData[] = array( - 'key' => 'zbsli_'.$k, // we have to add zbsli_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbsli_'.$k) - ); - - // add to remade $data for post-update updates - $data[$k] = $v; + } + } - } + #} ========= / CHECK FIELDS =========== - } + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - // copy over - $limitedFields = $limitedData; + // either ext source + setting, or set by the func call + if ( $do_not_update_blanks ) { - } // / if ID + // this setting says 'don't override filled-out data with blanks' + // so here we check through any passed blanks + convert to limitedFields + // only matters if $id is set (there is somt to update not add + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - } // / if do_not_update_blanks + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_lineitem( $data ); + // unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue + // unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbsli_x','val'=>y,'type'=>'%s')) + // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) + // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates + foreach ( $dbData as $k => $v ) { - #} ========= BUILD DATA =========== + $intV = (int) $v; - $update = false; $dataArr = array(); $typeArr = array(); + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { - if (is_array($limitedFields)){ + // add to update arr + $limitedData[] = array( + 'key' => 'zbsli_' . $k, // we have to add zbsli_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbsli_' . $k ), + ); - // LIMITED FIELDS - $update = true; + // add to remade $data for post-update updates + $data[ $k ] = $v; - // cycle through - foreach ($limitedFields as $field){ + } + } - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } + // copy over + $limitedFields = $limitedData; - } + } // / if ID - // add update time - if (!isset($dataArr['zbsli_lastupdated'])){ $dataArr['zbsli_lastupdated'] = time(); $typeArr[] = '%d'; } + } // / if do_not_update_blanks - } else { + #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== - // FULL UPDATE/INSERT + #} ========= BUILD DATA =========== - // UPDATE - $dataArr = array( + $update = false; + $dataArr = array(); + $typeArr = array(); - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, + if ( is_array( $limitedFields ) ) { - - 'zbsli_order' => $data['order'], - 'zbsli_title' => $data['title'], - 'zbsli_desc' => $data['desc'], - 'zbsli_quantity' => $data['quantity'], - 'zbsli_price' => $data['price'], - 'zbsli_currency' => $data['currency'], - 'zbsli_net' => $data['net'], - 'zbsli_discount' => $data['discount'], - 'zbsli_fee' => $data['fee'], - 'zbsli_shipping' => $data['shipping'], - 'zbsli_shipping_taxes' => $data['shipping_taxes'], - 'zbsli_shipping_tax' => $data['shipping_tax'], - 'zbsli_taxes' => $data['taxes'], - 'zbsli_tax' => $data['tax'], - 'zbsli_total' => $data['total'], - 'zbsli_lastupdated' => time(), + // LIMITED FIELDS + $update = true; - ); + // cycle through + foreach ( $limitedFields as $field ) { - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner + // some weird case where getting empties, so added check + if ( ! empty( $field['key'] ) ) { + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } + } - - '%d', - '%s', - '%s', - '%f', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%d', + // add update time + if ( ! isset( $dataArr['zbsli_lastupdated'] ) ) { + $dataArr['zbsli_lastupdated'] = time(); + $typeArr[] = '%d'; } + } else { + + // FULL UPDATE/INSERT + + // UPDATE + $dataArr = array( + + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, + + 'zbsli_order' => $data['order'], + 'zbsli_title' => $data['title'], + 'zbsli_desc' => $data['desc'], + 'zbsli_quantity' => $data['quantity'], + 'zbsli_price' => $data['price'], + 'zbsli_currency' => $data['currency'], + 'zbsli_net' => $data['net'], + 'zbsli_discount' => $data['discount'], + 'zbsli_fee' => $data['fee'], + 'zbsli_shipping' => $data['shipping'], + 'zbsli_shipping_taxes' => $data['shipping_taxes'], + 'zbsli_shipping_tax' => $data['shipping_tax'], + 'zbsli_taxes' => $data['taxes'], + 'zbsli_tax' => $data['tax'], + 'zbsli_total' => $data['total'], + 'zbsli_lastupdated' => time(), + + ); + + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner + + '%d', + '%s', + '%s', + '%f', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%d', + + ); + + if ( ! empty( $id ) && $id > 0 ) { + + // is update + $update = true; + + } else { + + // INSERT (get's few extra :D) + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbsli_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbsli_created'] = time(); + $typeArr[] = '%d'; + } + } + } - ); + #} ========= / BUILD DATA =========== - if (!empty($id) && $id > 0){ + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== - // is update - $update = true; + // if we're passing limitedFields we skip these, for now + // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 + if ( ! is_array( $limitedFields ) ) { - } else { + // verify uniques + if ( ! $this->verifyUniqueValues( $data, $id ) ) { + return false; // / fails unique field verify + } - // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $typeArr[] = '%d'; - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbsli_created'] = $data['created'];$typeArr[] = '%d'; - } else { - $dataArr['zbsli_created'] = time(); $typeArr[] = '%d'; - } - - } - - } - - #} ========= / BUILD DATA =========== - - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== - - // if we're passing limitedFields we skip these, for now - // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ - - // verify uniques - if (!$this->verifyUniqueValues($data,$id)) return false; // / fails unique field verify - - // verify not_empty - if (!$this->verifyNonEmptyValues($data)) return false; // / fails empty field verify - - } - - // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks($dataArr); - - #} ========= / CHECK force_uniques & not_empty ================ - #} ============================================================ - - - #} Check if ID present - if ($update){ - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['lineitems'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ - - - // if passing limitedFields instead of data, we ignore the following - // this doesn't work, because data is in args default as arr - //if (isset($data) && is_array($data)){ - // so... - if (!isset($limitedFields) || !is_array($limitedFields) || $limitedFields == -1){ - - - } // / if $data - - - // linked to anything? - if ($linkedObjType > 0 && $linkedObjID > 0){ - - // if not already got obj link, add it - $c = $this->DAL()->getObjsLinksLinkedToObj(array( - 'objtypefrom' => ZBS_TYPE_LINEITEM, // line item type (10) - 'objtypeto' => $linkedObjType, // obj type (e.g. inv) - 'objfromid' => $id, - 'objtoid' => $linkedObjID, - 'direction' => 'both', - 'count' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LINEITEM))); - - // add link (via append) if not present - if ($c <= 0) $this->DAL()->addUpdateObjLink(array( - 'data'=>array( - 'objtypefrom' => ZBS_TYPE_LINEITEM, - 'objtypeto' => $linkedObjType, - 'objfromid' => $id, - 'objtoid' => $linkedObjID, - // not req. 'owner' => $owner - ) - )); - - } - - - /* Not necessary - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ - - // IA General lineitem update (2.87+) - zeroBSCRM_FireInternalAutomator('lineitem.update',array( - 'id'=>$id, - 'againstid' => $id, - 'data'=> $dataArr - )); - - - - } */ - - - // Successfully updated - Return id - return $id; - - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); - - // FAILED update - return false; - - } - - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['lineitems'], - $dataArr, - $typeArr ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - - // linked to anything? - if ($linkedObjType > 0 && $linkedObjID > 0){ - - // if not already got obj link, add it - $c = $this->DAL()->getObjsLinksLinkedToObj(array( - 'objtypefrom' => ZBS_TYPE_LINEITEM, // line item type (10) - 'objtypeto' => $linkedObjType, // obj type (e.g. inv) - 'objfromid' => $newID, - 'objtoid' => $linkedObjID, - 'direction' => 'both', - 'count' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LINEITEM))); - - // add link (via append) if not present - if ($c <= 0) $this->DAL()->addUpdateObjLink(array( - 'data'=>array( - 'objtypefrom' => ZBS_TYPE_LINEITEM, - 'objtypeto' => $linkedObjType, - 'objfromid' => $newID, - 'objtoid' => $linkedObjID, - // not req. 'owner' => $owner - ) - )); - - } + // verify not_empty + if ( ! $this->verifyNonEmptyValues( $data ) ) { + return false; // / fails empty field verify + } + } - /* Not necessary - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT - if (!$silentInsert){ - - #} Add to automator - zeroBSCRM_FireInternalAutomator('lineitem.new',array( - 'id'=>$newID, - 'data'=>$dataArr, - 'extsource'=>$approvedExternalSource, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); - - } - */ - - return $newID; - - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); + // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections + $dataArr = $this->wpdbChecks( $dataArr ); + + #} ========= / CHECK force_uniques & not_empty ================ + #} ============================================================ + + #} Check if ID present + if ( $update ) { + + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['lineitems'], + $dataArr, + array( // where + 'ID' => $id, + ), + $typeArr, + array( // where data types + '%d', + ) + ) !== false ) { + + // if passing limitedFields instead of data, we ignore the following + // this doesn't work, because data is in args default as arr + // if (isset($data) && is_array($data)){ + // so... + if ( ! isset( $limitedFields ) || ! is_array( $limitedFields ) || $limitedFields == -1 ) { + + } // / if $data + + // linked to anything? + if ( $linkedObjType > 0 && $linkedObjID > 0 ) { + + // if not already got obj link, add it + $c = $this->DAL()->getObjsLinksLinkedToObj( + array( + 'objtypefrom' => ZBS_TYPE_LINEITEM, // line item type (10) + 'objtypeto' => $linkedObjType, // obj type (e.g. inv) + 'objfromid' => $id, + 'objtoid' => $linkedObjID, + 'direction' => 'both', + 'count' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LINEITEM ), + ) + ); + + // add link (via append) if not present + if ( $c <= 0 ) { + $this->DAL()->addUpdateObjLink( + array( + 'data' => array( + 'objtypefrom' => ZBS_TYPE_LINEITEM, + 'objtypeto' => $linkedObjType, + 'objfromid' => $id, + 'objtoid' => $linkedObjID, + // not req. 'owner' => $owner + ), + ) + ); + } + } - #} Failed to Insert - return false; + /* + Not necessary + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // UPDATING CONTACT + if (!$silentInsert){ - } + // IA General lineitem update (2.87+) + zeroBSCRM_FireInternalAutomator('lineitem.update',array( + 'id'=>$id, + 'againstid' => $id, + 'data'=> $dataArr + )); - } - return false; - } + } */ + // Successfully updated - Return id + return $id; + } else { - /** - * deletes a lineitem object - * - * NOTE! Not to be used directly, or if so, manually delete the objlinks for this item<->obj (e.g. inv) else garbage kept in objlinks table - * Use: deleteLineItemsForObject - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteLineitem($args=array()){ + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - global $ZBSCRM_t,$wpdb,$zbs; + // FAILED update + return false; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } + } else { + + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['lineitems'], + $dataArr, + $typeArr + ) > 0 ) { + + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + + // linked to anything? + if ( $linkedObjType > 0 && $linkedObjID > 0 ) { + + // if not already got obj link, add it + $c = $this->DAL()->getObjsLinksLinkedToObj( + array( + 'objtypefrom' => ZBS_TYPE_LINEITEM, // line item type (10) + 'objtypeto' => $linkedObjType, // obj type (e.g. inv) + 'objfromid' => $newID, + 'objtoid' => $linkedObjID, + 'direction' => 'both', + 'count' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LINEITEM ), + ) + ); + + // add link (via append) if not present + if ( $c <= 0 ) { + $this->DAL()->addUpdateObjLink( + array( + 'data' => array( + 'objtypefrom' => ZBS_TYPE_LINEITEM, + 'objtypeto' => $linkedObjType, + 'objfromid' => $newID, + 'objtoid' => $linkedObjID, + // not req. 'owner' => $owner + ), + ) + ); + } + } - 'id' => -1, - 'saveOrphans' => true, - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ - - - } - - return zeroBSCRM_db2_deleteGeneric($id,'lineitems'); - - } - - return false; - - } - - - /** - * deletes all lineitem objects assigned to another obj (quote,inv,trans) - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteLineItemsForObject($args=array()){ + /* + Not necessary + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // NEW CONTACT + if (!$silentInsert){ + + #} Add to automator + zeroBSCRM_FireInternalAutomator('lineitem.new',array( + 'id'=>$newID, + 'data'=>$dataArr, + 'extsource'=>$approvedExternalSource, + 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) + )); - global $ZBSCRM_t,$wpdb,$zbs; + } + */ - #} ============ LOAD ARGS ============= - $defaultArgs = array( + return $newID; - 'objID' => -1, - 'objType' => -1 + } else { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); - #} Check ID & Delete :) - $objID = (int)$objID; - if (!empty($objID) && $objID > 0 && !empty($objType) && $objType > 0) { - - $lineItems = $this->getLineitems(array('associatedObjType'=>$objType,'associatedObjID'=>$objID,'perPage'=>1000,'ignoreowner'=>true)); + #} Failed to Insert + return false; - $delcount = 0; - if (is_array($lineItems)) foreach ($lineItems as $li){ + } + } - $delcount += $this->deleteLineitem(array('id'=>$li['id'])); + return false; + } - // also delete the objlink for this - $this->DAL()->deleteObjLinks(array( - 'objtypefrom' => ZBS_TYPE_LINEITEM, - 'objtypeto' => $objType, - 'objfromid' => $li['id'], - 'objtoid' => $objID - )); + /** + * deletes a lineitem object + * + * NOTE! Not to be used directly, or if so, manually delete the objlinks for this item<->obj (e.g. inv) else garbage kept in objlinks table + * Use: deleteLineItemsForObject + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteLineitem( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'saveOrphans' => true, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - } + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - return $delcount; + // delete orphans? + if ( $saveOrphans === false ) { - } + } - return false; + return zeroBSCRM_db2_deleteGeneric( $id, 'lineitems' ); - } + } + return false; + } - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array lineitem (clean obj) - */ - private function tidy_lineitem($obj=false,$withCustomFields=false){ + /** + * deletes all lineitem objects assigned to another obj (quote,inv,trans) + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteLineItemsForObject( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'objID' => -1, + 'objType' => -1, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ + + #} Check ID & Delete :) + $objID = (int) $objID; + if ( ! empty( $objID ) && $objID > 0 && ! empty( $objType ) && $objType > 0 ) { + + $lineItems = $this->getLineitems( + array( + 'associatedObjType' => $objType, + 'associatedObjID' => $objID, + 'perPage' => 1000, + 'ignoreowner' => true, + ) + ); + + $delcount = 0; + if ( is_array( $lineItems ) ) { + foreach ( $lineItems as $li ) { + + $delcount += $this->deleteLineitem( array( 'id' => $li['id'] ) ); + + // also delete the objlink for this + $this->DAL()->deleteObjLinks( + array( + 'objtypefrom' => ZBS_TYPE_LINEITEM, + 'objtypeto' => $objType, + 'objfromid' => $li['id'], + 'objtoid' => $objID, + ) + ); - $res = false; + } + } - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = $obj->zbs_owner; + return $delcount; - - $res['order'] = (int)$obj->zbsli_order; - $res['title'] = $this->stripSlashes($obj->zbsli_title); - $res['desc'] = $this->stripSlashes($obj->zbsli_desc); - $res['quantity'] = zeroBSCRM_format_quantity( $this->stripSlashes( $obj->zbsli_quantity ) ); - $res['price'] = $this->stripSlashes($obj->zbsli_price); - $res['currency'] = $this->stripSlashes($obj->zbsli_currency); - $res['net'] = $this->stripSlashes($obj->zbsli_net); - $res['discount'] = $this->stripSlashes($obj->zbsli_discount); - $res['fee'] = $this->stripSlashes($obj->zbsli_fee); - $res['shipping'] = $this->stripSlashes($obj->zbsli_shipping); - $res['shipping_taxes'] = $this->stripSlashes($obj->zbsli_shipping_taxes); - $res['shipping_tax'] = $this->stripSlashes($obj->zbsli_shipping_tax); - $res['taxes'] = $this->stripSlashes($obj->zbsli_taxes); - $res['tax'] = $this->stripSlashes($obj->zbsli_tax); - $res['total'] = $this->stripSlashes($obj->zbsli_total); - $res['created'] = (int)$obj->zbsli_created; - $res['created_date'] = (isset($obj->zbsli_created) && $obj->zbsli_created > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsli_created) : false; - $res['lastupdated'] = (int)$obj->zbsli_lastupdated; - $res['lastupdated_date'] = (isset($obj->zbsli_lastupdated) && $obj->zbsli_lastupdated > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsli_lastupdated) : false; + } + return false; + } - } + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array lineitem (clean obj) + */ + private function tidy_lineitem( $obj = false, $withCustomFields = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = $obj->zbs_owner; + + $res['order'] = (int) $obj->zbsli_order; + $res['title'] = $this->stripSlashes( $obj->zbsli_title ); + $res['desc'] = $this->stripSlashes( $obj->zbsli_desc ); + $res['quantity'] = zeroBSCRM_format_quantity( $this->stripSlashes( $obj->zbsli_quantity ) ); + $res['price'] = $this->stripSlashes( $obj->zbsli_price ); + $res['currency'] = $this->stripSlashes( $obj->zbsli_currency ); + $res['net'] = $this->stripSlashes( $obj->zbsli_net ); + $res['discount'] = $this->stripSlashes( $obj->zbsli_discount ); + $res['fee'] = $this->stripSlashes( $obj->zbsli_fee ); + $res['shipping'] = $this->stripSlashes( $obj->zbsli_shipping ); + $res['shipping_taxes'] = $this->stripSlashes( $obj->zbsli_shipping_taxes ); + $res['shipping_tax'] = $this->stripSlashes( $obj->zbsli_shipping_tax ); + $res['taxes'] = $this->stripSlashes( $obj->zbsli_taxes ); + $res['tax'] = $this->stripSlashes( $obj->zbsli_tax ); + $res['total'] = $this->stripSlashes( $obj->zbsli_total ); + $res['created'] = (int) $obj->zbsli_created; + $res['created_date'] = ( isset( $obj->zbsli_created ) && $obj->zbsli_created > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbsli_created ) : false; + $res['lastupdated'] = (int) $obj->zbsli_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbsli_lastupdated ) && $obj->zbsli_lastupdated > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbsli_lastupdated ) : false; - return $res; + } - } + return $res; + } /** * Takes whatever lineitem data available and re-calculates net, total, tax etc. @@ -1128,24 +1341,22 @@ public function recalculate( $line_item = false ) { return false; } + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * This does so based on the objectModel! + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + private function db_ready_lineitem( $obj = false ) { - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * This does so based on the objectModel! - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - private function db_ready_lineitem($obj=false){ - - // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); - - } + // use the generic? (override here if necessary) + return $this->db_ready_obj( $obj ); + } - // =========== / LINEITEM ======================================================= - // =============================================================================== + // =========== / LINEITEM ======================================================= + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Logs.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Logs.php index 7394e27d4747..8fcd96945d79 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Logs.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Logs.php @@ -1,5 +1,6 @@ -> Logs -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Logs + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_logs extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_LOG; - protected $objectModel = array( - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'objtype' => array('fieldname' => 'zbsl_objtype', 'format' => 'int'), - 'objid' => array('fieldname' => 'zbsl_objid', 'format' => 'int'), - 'type' => array('fieldname' => 'zbsl_type', 'format' => 'str'), - 'shortdesc' => array('fieldname' => 'zbsl_shortdesc', 'format' => 'str'), - 'longdesc' => array('fieldname' => 'zbsl_longdesc', 'format' => 'str'), - 'pinned' => array('fieldname' => 'zbsl_pinned', 'format' => 'int'), - 'created' => array('fieldname' => 'zbsl_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsl_lastupdated', 'format' => 'uts'), - - ); - - - - /** - * Returns log types which count as 'contact' - * (These effect what updates 'last contacted' field against customer and 'latest contact log') - * - For now hard typed - */ + protected $objectType = ZBS_TYPE_LOG; + protected $objectModel = array( + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'objtype' => array( + 'fieldname' => 'zbsl_objtype', + 'format' => 'int', + ), + 'objid' => array( + 'fieldname' => 'zbsl_objid', + 'format' => 'int', + ), + 'type' => array( + 'fieldname' => 'zbsl_type', + 'format' => 'str', + ), + 'shortdesc' => array( + 'fieldname' => 'zbsl_shortdesc', + 'format' => 'str', + ), + 'longdesc' => array( + 'fieldname' => 'zbsl_longdesc', + 'format' => 'str', + ), + 'pinned' => array( + 'fieldname' => 'zbsl_pinned', + 'format' => 'int', + ), + 'created' => array( + 'fieldname' => 'zbsl_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsl_lastupdated', + 'format' => 'uts', + ), + + ); + + /** + * Returns log types which count as 'contact' + * (These effect what updates 'last contacted' field against customer and 'latest contact log') + * - For now hard typed + */ public $contact_log_types = array( 'call', 'email', 'mail', 'meeting', 'feedback', 'invoice__sent', 'quote__sent', 'feedback', 'tweet', 'facebook_post', 'other_contact' ); - function __construct($args=array()) { - - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - - } - - - // =============================================================================== - // =========== LOGS =========================================================== - - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ - - return $this->getLog(array('id'=>$ID)); - - } - - - /** - * returns full Log line +- details - * - * @param array $args Associative array of arguments - * key, fullDetails, default - * - * @return array result - */ - public function getLog($args=array()){ - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - // search args: - 'id' => -1, - - // include: - 'incMeta' => false, + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + } + + // =============================================================================== + // =========== LOGS =========================================================== + + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { + + return $this->getLog( array( 'id' => $ID ) ); + } + + /** + * returns full Log line +- details + * + * @param array $args Associative array of arguments + * key, fullDetails, default + * + * @return array result + */ + public function getLog( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // search args: + 'id' => -1, + + // include: + 'incMeta' => false, + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LOG ), // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LOG), // this'll let you not-check the owner of obj + #} ========== CHECK FIELDS ============ - // returns scalar ID of line - 'onlyID' => false + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} ========== CHECK FIELDS ============ - - // check id - $id = (int)$id; - if (empty($id) || $id <= 0) return false; + #} ========= / CHECK FIELDS =========== - #} ========= / CHECK FIELDS =========== - - #} Check key + #} Check key if ( $id ) { - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); - - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['logs']; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} ============= WHERE ================ + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['logs']; - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); + #} ============= WHERE ================ - #} ============ / WHERE ============== + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} ============ / WHERE ============== - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); - - - try { - - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $this->catchSQLError($e); - - } - - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { - - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID === true) return $potentialRes->ID; - - if ($incMeta) $potentialRes->meta = $this->DAL()->getMeta(array( - - 'objtype' => ZBS_TYPE_LOG, - 'objid' => $potentialRes->ID, - 'key' => 'logmeta', - 'fullDetails' => false, - 'default' => -1 - - )); - - return $this->tidy_log($potentialRes); - - } - - } // / if ID - - return $default; - - } - - - /** - * returns log lines for an obj - * - * @param array $args Associative array of arguments - * searchPhrase, sortByField, sortOrder, page, perPage - * - * @return array of tag lines - */ - public function getLogsForObj($args=array()){ - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // search args: - 'objtype' => -1, - 'objid' => -1, - 'searchPhrase' => '', // specify to search through all note descs - 'notetype' => -1, // specify a permified type to grab collection - 'notetypes' => -1, // specify an array of permified types to grab collection - 'only_pinned' => false, - 'meta_pair' => -1, // where array('key'=>x,'value'=>y) will find logs with this meta - - // return - 'incMeta' => false, - - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, - 'perPage' => 100, - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LOG) // this'll let you not-check the owner of obj + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership + + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); + + try { + + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); + + } catch ( Exception $e ) { + + #} General SQL Err + $this->catchSQLError( $e ); + + } + + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { + + #} Has results, tidy + return + + #} Only ID? return it directly + if ( $onlyID === true ) { + return $potentialRes->ID; + } + + if ( $incMeta ) { + $potentialRes->meta = $this->DAL()->getMeta( + array( + + 'objtype' => ZBS_TYPE_LOG, + 'objid' => $potentialRes->ID, + 'key' => 'logmeta', + 'fullDetails' => false, + 'default' => -1, + + ) + ); + } + + return $this->tidy_log( $potentialRes ); + + } + } // / if ID + + return $default; + } + + /** + * returns log lines for an obj + * + * @param array $args Associative array of arguments + * searchPhrase, sortByField, sortOrder, page, perPage + * + * @return array of tag lines + */ + public function getLogsForObj( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // search args: + 'objtype' => -1, + 'objid' => -1, + 'searchPhrase' => '', // specify to search through all note descs + 'notetype' => -1, // specify a permified type to grab collection + 'notetypes' => -1, // specify an array of permified types to grab collection + 'only_pinned' => false, + 'meta_pair' => -1, // where array('key'=>x,'value'=>y) will find logs with this meta + + // return + 'incMeta' => false, + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, + 'perPage' => 100, + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LOG ), // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} ========== CHECK FIELDS ============ - #} ========== CHECK FIELDS ============ + // ID + $objid = (int) $objid; + if ( empty( $objid ) || $objid <= 0 ) { + return false; + } - // ID - $objid = (int)$objid; - if (empty($objid) || $objid <= 0) return false; + // This was returning false when $objid was 0 (or -1) + if ( $objid < 0 ) { + return false; + } - // This was returning false when $objid was 0 (or -1) - if ($objid < 0) return false; + // check obtype is legit.. + $objtype = (int) $objtype; + if ( ! isset( $objtype ) || $objtype == -1 || $this->DAL()->objTypeKey( $objtype ) === -1 ) { + return false; + } - // check obtype is legit.. - $objtype = (int)$objtype; - if (!isset($objtype) || $objtype == -1 || $this->DAL()->objTypeKey($objtype) === -1) return false; - - #} ========= / CHECK FIELDS =========== + #} ========= / CHECK FIELDS =========== - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['logs']; + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['logs']; - #} ============= WHERE ================ + #} ============= WHERE ================ - #} objid + #} objid $wheres['zbsl_objid'] = array( 'zbsl_objid', '=', '%d', $objid ); - #} objtype - if (!empty($objtype) && $objtype !== -1) $wheres['zbsl_objtype'] = array('zbsl_objtype','=','%d',$objtype); - - #} notetype - if (!empty($notetype) && $notetype !== -1) $wheres['zbsl_type'] = array('zbsl_type','=','%s',$notetype); + #} objtype + if ( ! empty( $objtype ) && $objtype !== -1 ) { + $wheres['zbsl_objtype'] = array( 'zbsl_objtype', '=', '%d', $objtype ); + } - #} notetypes - if (is_array($notetypes) && count($notetypes) > 0){ + #} notetype + if ( ! empty( $notetype ) && $notetype !== -1 ) { + $wheres['zbsl_type'] = array( 'zbsl_type', '=', '%s', $notetype ); + } - // Generate escaped csv, e.g. 'Call','Email' - $notetypesStr = $this->build_csv($notetypes); + #} notetypes + if ( is_array( $notetypes ) && count( $notetypes ) > 0 ) { - // add it as a direct where clause to avoid double escaping - $wheres['direct'][] = array('zbsl_type IN ('.$notetypesStr.')',array()); + // Generate escaped csv, e.g. 'Call','Email' + $notetypesStr = $this->build_csv( $notetypes ); + // add it as a direct where clause to avoid double escaping + $wheres['direct'][] = array( 'zbsl_type IN (' . $notetypesStr . ')', array() ); - } + } - // pinned - if ( $only_pinned ){ + // pinned + if ( $only_pinned ) { - $wheres['direct'][] = array('zbsl_pinned = 1',array()); + $wheres['direct'][] = array( 'zbsl_pinned = 1', array() ); - } + } - #} Search - if (!empty($searchPhrase)) { - $wheres['zbsl_shortdesc'] = array('zbsl_shortdesc','LIKE','%s','%'.$searchPhrase.'%'); - $wheres['zbsl_longdesc'] = array('zbsl_longdesc','LIKE','%s','%'.$searchPhrase.'%'); - } + #} Search + if ( ! empty( $searchPhrase ) ) { + $wheres['zbsl_shortdesc'] = array( 'zbsl_shortdesc', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $wheres['zbsl_longdesc'] = array( 'zbsl_longdesc', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + } - // meta_pair + // meta_pair // @phan-suppress-next-line PhanImpossibleCondition -- This var is initialized by arbitrary data in $args. - if ( is_array( $meta_pair ) && isset( $meta_pair['key'] ) && isset( $meta_pair['value'] ) ){ - - // make a clean version - $meta_pair_key = $this->DAL()->makeSlug( $meta_pair['key'] ); - - // search for it - $wheres['log_meta'] = array('ID','IN',"(SELECT zbsm_objid FROM ".$ZBSCRM_t['meta']." WHERE zbsm_objtype = " . ZBS_TYPE_LOG . " AND zbsm_key = %s AND zbsm_val = %s)", array( $meta_pair_key, $meta_pair['value'] ) ); - - } - - #} ============ / WHERE =============== - - #} Build out any WHERE clauses - $wheresArr= $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE - - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); - - try { + if ( is_array( $meta_pair ) && isset( $meta_pair['key'] ) && isset( $meta_pair['value'] ) ) { - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + // make a clean version + $meta_pair_key = $this->DAL()->makeSlug( $meta_pair['key'] ); - } catch (Exception $e){ + // search for it + $wheres['log_meta'] = array( 'ID', 'IN', '(SELECT zbsm_objid FROM ' . $ZBSCRM_t['meta'] . ' WHERE zbsm_objtype = ' . ZBS_TYPE_LOG . ' AND zbsm_key = %s AND zbsm_val = %s)', array( $meta_pair_key, $meta_pair['value'] ) ); - #} General SQL Err - $this->catchSQLError($e); + } - } + #} ============ / WHERE =============== - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - if ($incMeta) $resDataLine->meta = $this->DAL()->getMeta(array( + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - 'objtype' => ZBS_TYPE_LOG, - 'objid' => $resDataLine->ID, - 'key' => 'logmeta', - 'fullDetails' => false, - 'default' => -1 + try { - )); - - // tidy - $resArr = $this->tidy_log($resDataLine); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - $res[] = $resArr; + } catch ( Exception $e ) { - } - } + #} General SQL Err + $this->catchSQLError( $e ); - return $res; - } + } + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - /** - * returns log lines, ignoring obj/owner - added to infill a few funcs ms added, not sure where used (not core) - * (zeroBS_searchLogs + allLogs) - * - * @param array $args Associative array of arguments - * searchPhrase, sortByField, sortOrder, page, perPage - * - * @return array of tag lines - */ - public function getLogsForANYObj($args=array()){ + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + if ( $incMeta ) { + $resDataLine->meta = $this->DAL()->getMeta( + array( - 'objtype' => -1, // optional + 'objtype' => ZBS_TYPE_LOG, + 'objid' => $resDataLine->ID, + 'key' => 'logmeta', + 'fullDetails' => false, + 'default' => -1, - 'searchPhrase' => -1, // specify to search through all note descs - 'notetype' => -1, // specify a permified type to grab collection - 'notetypes' => -1, // specify an array of permified types to grab collection + ) + ); + } - // return - 'incMeta' => false, + // tidy + $resArr = $this->tidy_log( $resDataLine ); - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, - 'perPage' => 100, + $res[] = $resArr; - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LOG) // this'll let you not-check the owner of obj + } + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + return $res; + } + + /** + * returns log lines, ignoring obj/owner - added to infill a few funcs ms added, not sure where used (not core) + * (zeroBS_searchLogs + allLogs) + * + * @param array $args Associative array of arguments + * searchPhrase, sortByField, sortOrder, page, perPage + * + * @return array of tag lines + */ + public function getLogsForANYObj( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'objtype' => -1, // optional + + 'searchPhrase' => -1, // specify to search through all note descs + 'notetype' => -1, // specify a permified type to grab collection + 'notetypes' => -1, // specify an array of permified types to grab collection + + // return + 'incMeta' => false, + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, + 'perPage' => 100, + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LOG ), // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ - // check obtype is legit - $objtype = (int)$objtype; + // check obtype is legit + $objtype = (int) $objtype; - #} ========= / CHECK FIELDS =========== + #} ========= / CHECK FIELDS =========== - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['logs']; + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['logs']; - #} ============= WHERE ================ + #} ============= WHERE ================ - #} objtype - if (!empty($objtype)) $wheres['zbsl_objtype'] = array('zbsl_objtype','=','%d',$objtype); + #} objtype + if ( ! empty( $objtype ) ) { + $wheres['zbsl_objtype'] = array( 'zbsl_objtype', '=', '%d', $objtype ); + } - #} notetype - if (!empty($notetype) && $notetype != -1) $wheres['zbsl_type'] = array('zbsl_type','=','%s',$notetype); + #} notetype + if ( ! empty( $notetype ) && $notetype != -1 ) { + $wheres['zbsl_type'] = array( 'zbsl_type', '=', '%s', $notetype ); + } - #} notetypes - if (is_array($notetypes) && count($notetypes) > 0){ - $notetypesStr = ''; - foreach ($notetypes as $nt){ - if (!empty($notetypesStr)) $notetypesStr .= ','; - $notetypesStr .= '"'.$nt.'"'; - } + #} notetypes + if ( is_array( $notetypes ) && count( $notetypes ) > 0 ) { + $notetypesStr = ''; + foreach ( $notetypes as $nt ) { + if ( ! empty( $notetypesStr ) ) { + $notetypesStr .= ','; + } + $notetypesStr .= '"' . $nt . '"'; + } + + $wheres['zbsl_types'] = array( 'zbsl_type', 'IN', '%s', '(' . $notetypesStr . ')' ); + } - $wheres['zbsl_types'] = array('zbsl_type','IN','%s','('.$notetypesStr.')'); - } + #} Search + if ( ! empty( $searchPhrase ) ) { + $wheres['zbsl_shortdesc'] = array( 'zbsl_shortdesc', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $wheres['zbsl_longdesc'] = array( 'zbsl_longdesc', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + } - #} Search - if (!empty($searchPhrase)) { - $wheres['zbsl_shortdesc'] = array('zbsl_shortdesc','LIKE','%s','%'.$searchPhrase.'%'); - $wheres['zbsl_longdesc'] = array('zbsl_longdesc','LIKE','%s','%'.$searchPhrase.'%'); - } + #} ============ / WHERE =============== - #} ============ / WHERE =============== + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Build out any WHERE clauses - $wheresArr= $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); + try { - try { + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + } catch ( Exception $e ) { - } catch (Exception $e){ + #} General SQL Err + $this->catchSQLError( $e ); - #} General SQL Err - $this->catchSQLError($e); + } - } + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { + if ( $incMeta ) { + $resDataLine->meta = $this->DAL()->getMeta( + array( - if ($incMeta) $resDataLine->meta = $this->DAL()->getMeta(array( + 'objtype' => ZBS_TYPE_LOG, + 'objid' => $resDataLine->ID, + 'key' => 'logmeta', + 'fullDetails' => false, + 'default' => -1, - 'objtype' => ZBS_TYPE_LOG, - 'objid' => $resDataLine->ID, - 'key' => 'logmeta', - 'fullDetails' => false, - 'default' => -1 + ) + ); + } - )); - - // tidy - $resArr = $this->tidy_log($resDataLine); + // tidy + $resArr = $this->tidy_log( $resDataLine ); - $res[] = $resArr; + $res[] = $resArr; - } - } + } + } - return $res; - } + return $res; + } + + /** + * Returns a count of logs (owned) + * + * @return int count + */ + public function getLogCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'withType' => false, // will be str if used + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LOG ), // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + $whereArr = array(); - /** - * Returns a count of logs (owned) - * - * @return int count - */ - public function getLogCount($args=array()){ + if ( $withType !== false && ! empty( $withType ) ) { + $whereArr['status'] = array( 'zbsl_type', '=', '%s', $withType ); + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_LOG, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + } + + /** + * adds or updates a log object + * + * @param array $args Associative array of arguments + * id (not req.), owner (not req.) data -> key/val + * + * @return int line ID + */ + public function addUpdateLog( $args = array() ) { + + global $zbs, $ZBSCRM_t, $wpdb; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'owner' => -1, + + // fields (directly) + 'data' => array( + + 'objtype' => -1, + 'objid' => -1, + 'type' => '', // log type e.g. zbsOc1 (zbsencoded) or custom e.g. "ALARM" + 'shortdesc' => '', + 'longdesc' => '', + 'pinned' => -1, + + 'meta' => -1, // can be any obj which'll be stored in meta table :) + + 'created' => -1, // override date? :( + + ), + + // where this is true, if a log of matching description strings and type are added to a single object + // no add or update will be enacted + 'ignore_if_existing_desc_type' => false, + + // where this is true, if a log with the given array('key','value') exists against an objid/type + // no add or update will be enacted + 'ignore_if_meta_matching' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - // Search/Filtering (leave as false to ignore) - 'withType' => false, // will be str if used + #} ========== CHECK FIELDS ============ - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LOG), // this'll let you not-check the owner of obj + $id = (int) $id; - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + // if owner = -1, add current + if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $owner = zeroBSCRM_user(); + } - $whereArr = array(); + // check obtype is legit + $data['objtype'] = (int) $data['objtype']; + if ( ! isset( $data['objtype'] ) || $data['objtype'] == -1 || $this->DAL()->objTypeKey( $data['objtype'] ) === -1 ) { + return false; + } - if ($withType !== false && !empty($withType)) $whereArr['status'] = array('zbsl_type','=','%s',$withType); + // check id present + legit + $data['objid'] = (int) $data['objid']; + if ( empty( $data['objid'] ) || $data['objid'] <= 0 ) { + return false; + } - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_LOG, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - } + // check type not empty + if ( empty( $data['type'] ) ) { + return false; + } + // check for existing log which has same type and description values + $has_desc_matching_record = false; + if ( $ignore_if_existing_desc_type ) { - /** - * adds or updates a log object - * - * @param array $args Associative array of arguments - * id (not req.), owner (not req.) data -> key/val - * - * @return int line ID - */ - public function addUpdateLog($args=array()){ + // find existing - will become unperformant if a contact ever gets 10's of thousands of notes of a type + $existing_logs = $this->getLogsForObj( + array( - global $zbs,$ZBSCRM_t,$wpdb; + 'objtype' => $data['objtype'], + 'objid' => $data['objid'], + 'notetype' => $data['type'], + 'page' => -1, + 'perPage' => -1, - #} ============ LOAD ARGS ============= - $defaultArgs = array( + ) + ); - 'id' => -1, - 'owner' => -1, + if ( is_array( $existing_logs ) ) { - // fields (directly) - 'data' => array( + foreach ( $existing_logs as $log ) { - 'objtype' => -1, - 'objid' => -1, - 'type' => '', // log type e.g. zbsOc1 (zbsencoded) or custom e.g. "ALARM" - 'shortdesc' => '', - 'longdesc' => '', - 'pinned' => -1, + if ( $log['shortdesc'] == $data['shortdesc'] + && $log['longdesc'] == $data['longdesc'] ) { - 'meta' => -1, // can be any obj which'll be stored in meta table :) + // log with this type and matching description strings already exists against this object + $has_desc_matching_record = true; - 'created' => -1 // override date? :( - - ), + } + } + } + } - // where this is true, if a log of matching description strings and type are added to a single object - // no add or update will be enacted - 'ignore_if_existing_desc_type' => false, + // check for exsting with meta + $has_meta_matching_record = false; + // @phan-suppress-next-line PhanImpossibleCondition -- This var is initialized by arbitrary data in $args. + if ( is_array( $ignore_if_meta_matching ) && isset( $ignore_if_meta_matching['key'] ) && isset( $ignore_if_meta_matching['value'] ) ) { - // where this is true, if a log with the given array('key','value') exists against an objid/type - // no add or update will be enacted - 'ignore_if_meta_matching' => false, + // find existing + $existing_logs = $this->getLogsForObj( + array( - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + 'objtype' => $data['objtype'], + 'objid' => $data['objid'], + 'meta_pair' => array( + 'key' => $ignore_if_meta_matching['key'], + 'value' => $ignore_if_meta_matching['value'], + ), + ) + ); - #} ========== CHECK FIELDS ============ + if ( is_array( $existing_logs ) && count( $existing_logs ) > 0 ) { - $id = (int)$id; + // log with this meta already exists against this object + $has_meta_matching_record = true; - // if owner = -1, add current - if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $owner = zeroBSCRM_user(); + } } - // check obtype is legit - $data['objtype'] = (int)$data['objtype']; - if (!isset($data['objtype']) || $data['objtype'] == -1 || $this->DAL()->objTypeKey($data['objtype']) === -1) return false; - - // check id present + legit - $data['objid'] = (int)$data['objid']; - if (empty($data['objid']) || $data['objid'] <= 0) return false; + // here we allow either or | both | none + // this lets us say 'is there a record with these meta + matching short/long desc' together - // check type not empty - if (empty($data['type'])) return false; + // both + if ( $ignore_if_existing_desc_type + && + is_array( $ignore_if_meta_matching ) && isset( $ignore_if_meta_matching['key'] ) && isset( $ignore_if_meta_matching['value'] ) ) { - // check for existing log which has same type and description values - $has_desc_matching_record = false; - if ( $ignore_if_existing_desc_type ){ + // both or fail + if ( $has_meta_matching_record && $has_desc_matching_record ) { - // find existing - will become unperformant if a contact ever gets 10's of thousands of notes of a type - $existing_logs = $this->getLogsForObj( array( + return false; - 'objtype' => $data['objtype'], - 'objid' => $data['objid'], - 'notetype' => $data['type'], - 'page' => -1, - 'perPage' => -1, + } - )); + // either or + } elseif ( $ignore_if_existing_desc_type + || + is_array( $ignore_if_meta_matching ) && isset( $ignore_if_meta_matching['key'] ) && isset( $ignore_if_meta_matching['value'] ) ) { - if ( is_array( $existing_logs ) ){ + // either = fail + if ( $has_meta_matching_record || $has_desc_matching_record ) { - foreach ( $existing_logs as $log ){ + return false; - if ( $log['shortdesc'] == $data['shortdesc'] - && $log['longdesc'] == $data['longdesc'] ){ - - // log with this type and matching description strings already exists against this object - $has_desc_matching_record = true; - - } - - } - - } - - } + } + } - // check for exsting with meta - $has_meta_matching_record = false; - // @phan-suppress-next-line PhanImpossibleCondition -- This var is initialized by arbitrary data in $args. - if ( is_array( $ignore_if_meta_matching ) && isset( $ignore_if_meta_matching['key'] ) && isset( $ignore_if_meta_matching['value'] ) ){ + #} ========= / CHECK FIELDS =========== + + $dataArr = array( + + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $owner, + + // fields + 'zbsl_objtype' => $data['objtype'], + 'zbsl_objid' => $data['objid'], + 'zbsl_type' => $data['type'], + 'zbsl_shortdesc' => $data['shortdesc'], + 'zbsl_longdesc' => $data['longdesc'], + 'zbsl_pinned' => $data['pinned'], + 'zbsl_lastupdated' => time(), + ); + + $dataTypes = array( // field data types + '%d', + + '%d', + '%d', + '%s', + '%s', + '%s', + '%d', + '%d', + ); + + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbsl_created'] = $data['created']; + $dataTypes[] = '%d'; + } - // find existing - $existing_logs = $this->getLogsForObj( array( + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { + + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) + + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['logs'], + $dataArr, + array( // where + 'ID' => $id, + ), + $dataTypes, + array( // where data types + '%d', + ) + ) !== false ) { - 'objtype' => $data['objtype'], - 'objid' => $data['objid'], - 'meta_pair' => array( - 'key' => $ignore_if_meta_matching['key'], - 'value' => $ignore_if_meta_matching['value'], - ) + // any meta + if ( isset( $data['meta'] ) && is_array( $data['meta'] ) ) { - )); + // add/update each meta key pair + foreach ( $data['meta'] as $k => $v ) { - if ( is_array( $existing_logs ) && count( $existing_logs ) > 0 ){ + // simple add + $this->DAL()->updateMeta( ZBS_TYPE_LOG, $id, $this->DAL()->makeSlug( $k ), $v ); - // log with this meta already exists against this object - $has_meta_matching_record = true; + } + } - } + #} Internal Automator + zeroBSCRM_FireInternalAutomator( + 'log.update', + array( + 'id' => $id, + 'logagainst' => $data['objid'], + 'logagainsttype' => $data['objtype'], + 'logtype' => $data['type'], + 'logshortdesc' => $data['shortdesc'], + 'loglongdesc' => $data['longdesc'], + ) + ); - } + // Successfully updated - Return id + return $id; - // here we allow either or | both | none - // this lets us say 'is there a record with these meta + matching short/long desc' together - - // both - if ( - $ignore_if_existing_desc_type - && - is_array( $ignore_if_meta_matching ) && isset( $ignore_if_meta_matching['key'] ) && isset( $ignore_if_meta_matching['value'] ) ){ - - // both or fail - if ( $has_meta_matching_record && $has_desc_matching_record ){ - - return false; - - } - - // either or - } else if ( - $ignore_if_existing_desc_type - || - is_array( $ignore_if_meta_matching ) && isset( $ignore_if_meta_matching['key'] ) && isset( $ignore_if_meta_matching['value'] ) ){ + } else { - // either = fail - if ( $has_meta_matching_record || $has_desc_matching_record ){ - - return false; + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - } - - } - - #} ========= / CHECK FIELDS =========== - - $dataArr = array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $owner, - - // fields - 'zbsl_objtype' => $data['objtype'], - 'zbsl_objid' => $data['objid'], - 'zbsl_type' => $data['type'], - 'zbsl_shortdesc' => $data['shortdesc'], - 'zbsl_longdesc' => $data['longdesc'], - 'zbsl_pinned' => $data['pinned'], - 'zbsl_lastupdated' => time() - ); - - $dataTypes = array( // field data types - '%d', - - '%d', - '%d', - '%s', - '%s', - '%s', - '%d', - '%d' - ); - - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbsl_created'] = $data['created']; $dataTypes[] = '%d'; - } - - - if (isset($id) && !empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['logs'], - $dataArr, - array( // where - 'ID' => $id - ), - $dataTypes, - array( // where data types - '%d' - )) !== false){ - - // any meta - if ( isset( $data['meta']) && is_array( $data['meta'] ) ){ + // FAILED update + return false; - // add/update each meta key pair - foreach ( $data['meta'] as $k => $v ){ - - // simple add - $this->DAL()->updateMeta( ZBS_TYPE_LOG, $id, $this->DAL()->makeSlug( $k ), $v ); - - } - - } - - #} Internal Automator - zeroBSCRM_FireInternalAutomator('log.update',array( - 'id'=>$id, - 'logagainst'=>$data['objid'], - 'logagainsttype'=>$data['objtype'], - 'logtype'=> $data['type'], - 'logshortdesc' => $data['shortdesc'], - 'loglongdesc' => $data['longdesc'] - )); - - // Successfully updated - Return id - return $id; + } + } else { - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); + // set created if not set + if ( ! isset( $dataArr['zbsl_created'] ) ) { + $dataArr['zbsl_created'] = time(); + $dataTypes[] = '%d'; + } - // FAILED update - return false; - - } - - } else { - - // set created if not set - if (!isset($dataArr['zbsl_created'])) { - $dataArr['zbsl_created'] = time(); $dataTypes[] = '%d'; - } - - // add team etc - $dataArr['zbs_site'] = zeroBSCRM_site(); $dataTypes[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $dataTypes[] = '%d'; - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['logs'], - $dataArr, - $dataTypes ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - - // any meta - if ( isset( $data['meta']) && is_array( $data['meta'] ) ){ - - // add/update each meta key pair - foreach ( $data['meta'] as $k => $v ){ - - // simple add - $this->DAL()->updateMeta( ZBS_TYPE_LOG, $newID, $this->DAL()->makeSlug( $k ), $v ); - - } - - } - - #} Internal Automator - if (!empty($newID)){ - - zeroBSCRM_FireInternalAutomator('log.new',array( - 'id'=>$newID, - 'logagainst'=>$data['objid'], - 'logagainsttype'=>$data['objtype'], - 'logtype'=> $data['type'], - 'logshortdesc' => $data['shortdesc'], - 'loglongdesc' => $data['longdesc'] - )); - - } - - return $newID; - - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); - - #} Failed to Insert - return false; - - } - - } - - return false; - - } - - /** - * deletes a Log object - * NOTE! this doesn't yet delete any META! - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteLog($args=array()){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // add team etc + $dataArr['zbs_site'] = zeroBSCRM_site(); + $dataTypes[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $dataTypes[] = '%d'; - 'id' => -1 + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['logs'], + $dataArr, + $dataTypes + ) > 0 ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) return zeroBSCRM_db2_deleteGeneric($id,'logs'); - - return false; - - } - - /** - * Pins a log object to its contact - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function set_log_pin_status( $args = array() ){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - 'pinned' => 1 - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + // any meta + if ( isset( $data['meta'] ) && is_array( $data['meta'] ) ) { - if ( $pinned !== 1 ){ - $pinned = -1; - } + // add/update each meta key pair + foreach ( $data['meta'] as $k => $v ) { - // attempt update - return $wpdb->update( - $ZBSCRM_t['logs'], - array( - 'zbsl_pinned' => $pinned - ), - array( // where - 'ID' => $id - ), - array( // field data types - '%d', - ), - array( // where data types - '%d' - )); + // simple add + $this->DAL()->updateMeta( ZBS_TYPE_LOG, $newID, $this->DAL()->makeSlug( $k ), $v ); - } + } + } - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_log($obj=false){ + #} Internal Automator + if ( ! empty( $newID ) ) { - $res = false; + zeroBSCRM_FireInternalAutomator( + 'log.new', + array( + 'id' => $newID, + 'logagainst' => $data['objid'], + 'logagainsttype' => $data['objtype'], + 'logtype' => $data['type'], + 'logshortdesc' => $data['shortdesc'], + 'loglongdesc' => $data['longdesc'], + ) + ); + + } + + return $newID; + + } else { + + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - $res['owner'] = $obj->zbs_owner; - - // added these two for backward compatibility / alias of (TROY modifications): - // please use owner ideally :) - $res['authorid'] = $obj->zbs_owner; - $res['author'] = get_the_author_meta('display_name',$obj->zbs_owner); + #} Failed to Insert + return false; - $res['objtype'] = $obj->zbsl_objtype; - $res['objid'] = $obj->zbsl_objid; + } + } - $res['type'] = $this->stripSlashes($obj->zbsl_type); - $res['shortdesc'] = $this->stripSlashes($obj->zbsl_shortdesc); - $res['longdesc'] = $this->stripSlashes($obj->zbsl_longdesc); - $res['pinned'] = ( (int)$obj->zbsl_pinned === 1 ); - - // to maintain old obj more easily, here we refine created into datestamp - $res['created'] = zeroBSCRM_locale_utsToDatetime($obj->zbsl_created); - $res['createduts'] = $obj->zbsl_created; // this is the UTS (int14) - - $res['lastupdated'] = $obj->zbsl_lastupdated; + return false; + } + + /** + * deletes a Log object + * NOTE! this doesn't yet delete any META! + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteLog( $args = array() ) { + + global $ZBSCRM_t, $wpdb; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - if (isset($obj->meta)) $res['meta'] = $obj->meta; + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + return zeroBSCRM_db2_deleteGeneric( $id, 'logs' ); + } - } + return false; + } + + /** + * Pins a log object to its contact + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function set_log_pin_status( $args = array() ) { + + global $ZBSCRM_t, $wpdb; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'pinned' => 1, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - return $res; + if ( $pinned !== 1 ) { + $pinned = -1; + } + // attempt update + return $wpdb->update( + $ZBSCRM_t['logs'], + array( + 'zbsl_pinned' => $pinned, + ), + array( // where + 'ID' => $id, + ), + array( // field data types + '%d', + ), + array( // where data types + '%d', + ) + ); + } + + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_log( $obj = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + $res['owner'] = $obj->zbs_owner; + + // added these two for backward compatibility / alias of (TROY modifications): + // please use owner ideally :) + $res['authorid'] = $obj->zbs_owner; + $res['author'] = get_the_author_meta( 'display_name', $obj->zbs_owner ); + + $res['objtype'] = $obj->zbsl_objtype; + $res['objid'] = $obj->zbsl_objid; + + $res['type'] = $this->stripSlashes( $obj->zbsl_type ); + $res['shortdesc'] = $this->stripSlashes( $obj->zbsl_shortdesc ); + $res['longdesc'] = $this->stripSlashes( $obj->zbsl_longdesc ); + $res['pinned'] = ( (int) $obj->zbsl_pinned === 1 ); + + // to maintain old obj more easily, here we refine created into datestamp + $res['created'] = zeroBSCRM_locale_utsToDatetime( $obj->zbsl_created ); + $res['createduts'] = $obj->zbsl_created; // this is the UTS (int14) + + $res['lastupdated'] = $obj->zbsl_lastupdated; + + if ( isset( $obj->meta ) ) { + $res['meta'] = $obj->meta; + } + } - } - - /** - * Translates a clear text log type to a lowercase (kinda) permalink - * ... this is kinda DAL1 legacy - * - * @param string - * - * @return string - */ - public function logTypeIn($str=''){ - - $x = str_replace(' ','_',$str); - $x = str_replace(':','_',$x); - return strtolower($x); - - } - - /** - * Translates a db text log type to a clear text output - * ... this is kinda DAL1 legacy - * *UNTESTED - * - * @param string - * - * @return string - */ - public function logTypeOut($str=''){ - - $x = str_replace('_',' ',$str); - $x = str_replace(' ',': ',$x); - return ucwords($x); - - } - - - - // =========== / LOGS ======================================================= - // =============================================================================== + return $res; + } + + /** + * Translates a clear text log type to a lowercase (kinda) permalink + * ... this is kinda DAL1 legacy + * + * @param string + * + * @return string + */ + public function logTypeIn( $str = '' ) { + + $x = str_replace( ' ', '_', $str ); + $x = str_replace( ':', '_', $x ); + return strtolower( $x ); + } + + /** + * Translates a db text log type to a clear text output + * ... this is kinda DAL1 legacy + * *UNTESTED + * + * @param string + * + * @return string + */ + public function logTypeOut( $str = '' ) { + + $x = str_replace( '_', ' ', $str ); + $x = str_replace( ' ', ': ', $x ); + return ucwords( $x ); + } + + // =========== / LOGS ======================================================= + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.QuoteTemplates.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.QuoteTemplates.php index 022b1e9bc481..5c52b5593f36 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.QuoteTemplates.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.QuoteTemplates.php @@ -1,5 +1,6 @@ -> Quote Templates -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Quote Templates + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_quotetemplates extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_QUOTETEMPLATE; - protected $objectDBPrefix = 'zbsqt_'; - protected $objectModel = array( + protected $objectType = ZBS_TYPE_QUOTETEMPLATE; + protected $objectDBPrefix = 'zbsqt_'; + protected $objectModel = array( // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), // other fields - 'title' => array( - 'fieldname' => 'zbsqt_title', - 'format' => 'str', - 'max_len' => 255 - ), - 'value' => array('fieldname' => 'zbsqt_value', 'format' => 'decimal'), - 'date_str' => array('fieldname' => 'zbsqt_date_str', 'format' => 'str'), - 'date' => array('fieldname' => 'zbsqt_date', 'format' => 'uts'), - 'content' => array('fieldname' => 'zbsqt_content', 'format' => 'str'), - 'notes' => array('fieldname' => 'zbsqt_notes', 'format' => 'str'), - 'currency' => array( - 'fieldname' => 'zbsqt_currency', - 'format' => 'curr', - 'max_len' => 4 - ), - 'created' => array('fieldname' => 'zbsqt_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsqt_lastupdated', 'format' => 'uts'), - - ); - - - function __construct($args=array()) { - + 'title' => array( + 'fieldname' => 'zbsqt_title', + 'format' => 'str', + 'max_len' => 255, + ), + 'value' => array( + 'fieldname' => 'zbsqt_value', + 'format' => 'decimal', + ), + 'date_str' => array( + 'fieldname' => 'zbsqt_date_str', + 'format' => 'str', + ), + 'date' => array( + 'fieldname' => 'zbsqt_date', + 'format' => 'uts', + ), + 'content' => array( + 'fieldname' => 'zbsqt_content', + 'format' => 'str', + ), + 'notes' => array( + 'fieldname' => 'zbsqt_notes', + 'format' => 'str', + ), + 'currency' => array( + 'fieldname' => 'zbsqt_currency', + 'format' => 'curr', + 'max_len' => 4, + ), + 'created' => array( + 'fieldname' => 'zbsqt_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsqt_lastupdated', + 'format' => 'uts', + ), + + ); + + function __construct( $args = array() ) { #} =========== LOAD ARGS ============== $defaultArgs = array( - //'tag' => false, + // 'tag' => false, - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } #} =========== / LOAD ARGS ============= - - } - // =============================================================================== - // =========== QUOTETEMPLATE ======================================================= + // =============================================================================== + // =========== QUOTETEMPLATE ======================================================= - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { - return $this->getQuotetemplate($ID); - - } - - /** - * returns full quotetemplate line +- details - * - * @param int id quotetemplate id - * @param array $args Associative array of arguments - * - * @return array quotetemplate object - */ - public function getQuotetemplate($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( + return $this->getQuotetemplate( $ID ); + } - // with what? - 'withOwner' => false, + /** + * returns full quotetemplate line +- details + * + * @param int id quotetemplate id + * @param array $args Associative array of arguments + * + * @return array quotetemplate object + */ + public function getQuotetemplate( $id = -1, $args = array() ) { - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTETEMPLATE), // this'll let you not-check the owner of obj + global $zbs; - // returns scalar ID of line - 'onlyID' => false, + #} =========== LOAD ARGS ============== + $defaultArgs = array( - 'fields' => false // false = *, array = fieldnames + // with what? + 'withOwner' => false, - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check ID - $id = (int)$id; - if ( - (!empty($id) && $id > 0) - || - (!empty($email)) - || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTETEMPLATE ), // this'll let you not-check the owner of obj - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; + // returns scalar ID of line + 'onlyID' => false, + 'fields' => false, // false = *, array = fieldnames - #} ============= PRE-QUERY ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - $selector = 'quotetemplate.*'; + #} Check ID + $id = (int) $id; + if ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $email ) ) + || + ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) + ) { + + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $extraSelect = ''; + + #} ============= PRE-QUERY ============ + + $selector = 'quotetemplate.*'; if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $selector = ''; - - // always needs id, so add if not present - if (!in_array('ID',$fields)) $selector = 'quotetemplate.ID'; - - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'quotetemplate.'.$f; - } - } else if ($onlyID){ - $selector = 'quotetemplate.ID'; - } + $selector = ''; - #} ============ / PRE-QUERY =========== + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'quotetemplate.ID'; + } + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'quotetemplate.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'quotetemplate.ID'; + } - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['quotetemplates'].' as quotetemplate'; - #} ============= WHERE ================ + #} ============ / PRE-QUERY =========== - if (!empty($id) && $id > 0){ + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['quotetemplates'] . ' as quotetemplate'; + #} ============= WHERE ================ - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); + if ( ! empty( $id ) && $id > 0 ) { - } + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - #} ============ / WHERE ============== + } - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} ============ / WHERE ============== - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'quotetemplate'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'quotetemplate' ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - try { + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + try { - } catch (Exception $e){ + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - #} General SQL Err - $this->catchSQLError($e); + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + } - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID) return $potentialRes->ID; - - // tidy - if (is_array($fields)){ - // guesses fields based on table col names - $res = $this->lazyTidyGeneric($potentialRes); - } else { - // proper tidy - $res = $this->tidy_quotetemplate($potentialRes,false); - } + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - /*if ($withTags){ + #} Has results, tidy + return - // add all tags lines - $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_QUOTETEMPLATE,'objid'=>$potentialRes->ID)); - - }*/ + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } - return $res; + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_quotetemplate( $potentialRes, false ); + } - } + /* + if ($withTags){ - } // / if ID + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_QUOTETEMPLATE,'objid'=>$potentialRes->ID)); - return false; + }*/ - } + return $res; - /** - * returns quotetemplate detail lines - * - * @param array $args Associative array of arguments - * - * @return array of quotetemplate lines - */ - public function getQuotetemplates($args=array()){ + } + } // / if ID - global $zbs; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( + return false; + } - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches which fields? - 'inArr' => false, - //'isTagged' => false, // 1x INT OR array(1,2,3) - //'isNotTagged' => false, // 1x INT OR array(1,2,3) - 'ownedBy' => false, - 'olderThan' => false, // uts - 'newerThan' => false, // uts - //'hasStatus' => false, // Lead (this takes over from the quick filter post 19/6/18) - //'otherStatus' => false, // status other than 'Lead' + /** + * returns quotetemplate detail lines + * + * @param array $args Associative array of arguments + * + * @return array of quotetemplate lines + */ + public function getQuotetemplates( $args = array() ) { - // returns - 'count' => false, - 'withOwner' => false, - 'checkDefaults' => false, // if true returns 'default' value too (is one of our defaults) + global $zbs; - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 100, - 'whereCase' => 'AND', // DEFAULT = AND + #} ============ LOAD ARGS ============= + $defaultArgs = array( - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTETEMPLATE), // this'll let you not-check the owner of obj - GLOBAL FOR NOW + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => '', // searches which fields? + 'inArr' => false, + // 'isTagged' => false, // 1x INT OR array(1,2,3) + // 'isNotTagged' => false, // 1x INT OR array(1,2,3) + 'ownedBy' => false, + 'olderThan' => false, // uts + 'newerThan' => false, // uts + // 'hasStatus' => false, // Lead (this takes over from the quick filter post 19/6/18) + // 'otherStatus' => false, // status other than 'Lead' + + // returns + 'count' => false, + 'withOwner' => false, + 'checkDefaults' => false, // if true returns 'default' value too (is one of our defaults) + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 100, + 'whereCase' => 'AND', // DEFAULT = AND + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTETEMPLATE ), // this'll let you not-check the owner of obj - GLOBAL FOR NOW + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + global $ZBSCRM_t, $wpdb, $zbs; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; - global $ZBSCRM_t,$wpdb,$zbs; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; + #} ============= PRE-QUERY ============ - #} ============= PRE-QUERY ============ + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); - #} Capitalise this - $sortOrder = strtoupper($sortOrder); + #} If just count, turn off any extra gumpf + if ( $count ) { + $withOwner = false; + } - #} If just count, turn off any extra gumpf - if ($count) { - $withOwner = false; - } + #} ============ / PRE-QUERY =========== - #} ============ / PRE-QUERY =========== + #} Build query + $query = 'SELECT quotetemplate.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['quotetemplates'] . ' as quotetemplate' . $joinQ; - #} Build query - $query = "SELECT quotetemplate.*".$extraSelect." FROM ".$ZBSCRM_t['quotetemplates'].' as quotetemplate'.$joinQ; + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(quotetemplate.ID) FROM ' . $ZBSCRM_t['quotetemplates'] . ' as quotetemplate' . $joinQ; + } - #} Count override - if ($count) $query = "SELECT COUNT(quotetemplate.ID) FROM ".$ZBSCRM_t['quotetemplates'].' as quotetemplate'.$joinQ; + #} ============= WHERE ================ - #} ============= WHERE ================ + #} Add Search phrase + if ( ! empty( $searchPhrase ) ) { - #} Add Search phrase - if (!empty($searchPhrase)){ + // search? - ALL THESE COLS should probs have index of FULLTEXT in db? + $searchWheres = array(); + $searchWheres['search_title'] = array( 'zbsqt_title', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_content'] = array( 'zbsqt_content', 'LIKE', '%s', '%' . $searchPhrase . '%' ); - // search? - ALL THESE COLS should probs have index of FULLTEXT in db? - $searchWheres = array(); - $searchWheres['search_title'] = array('zbsqt_title','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_content'] = array('zbsqt_content','LIKE','%s','%'.$searchPhrase.'%'); + // This generates a query like 'zbsqt_fname LIKE %s OR zbsqt_lname LIKE %s', + // which we then need to include as direct subquery (below) in main query :) + $searchQueryArr = $this->buildWheres( $searchWheres, '', array(), 'OR', false ); - // This generates a query like 'zbsqt_fname LIKE %s OR zbsqt_lname LIKE %s', - // which we then need to include as direct subquery (below) in main query :) - $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - - if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ + if ( is_array( $searchQueryArr ) && isset( $searchQueryArr['where'] ) && ! empty( $searchQueryArr['where'] ) ) { - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + // add it + $wheres['direct'][] = array( '(' . $searchQueryArr['where'] . ')', $searchQueryArr['params'] ); - } + } + } - } + #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { - #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) - if (is_array($inArr) && count($inArr) > 0){ + // clean for ints + $inArrChecked = array(); + foreach ( $inArr as $x ) { + $inArrChecked[] = (int) $x; } - // clean for ints - $inArrChecked = array(); foreach ($inArr as $x){ $inArrChecked[] = (int)$x; } + // add where + $wheres['inarray'] = array( 'ID', 'IN', '(' . implode( ',', $inArrChecked ) . ')' ); - // add where - $wheres['inarray'] = array('ID','IN','('.implode(',',$inArrChecked).')'); + } - } + #} Owned by + if ( ! empty( $ownedBy ) && $ownedBy > 0 ) { - #} Owned by - if (!empty($ownedBy) && $ownedBy > 0){ - - // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) - // but this is only here until MIGRATED to db2 globally - //$wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); - // Use obj links now - $wheres['ownedBy'] = array('zbs_owner','=','%s',$ownedBy); + // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) + // but this is only here until MIGRATED to db2 globally + // $wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); + // Use obj links now + $wheres['ownedBy'] = array( 'zbs_owner', '=', '%s', $ownedBy ); - } + } // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed // quick addition for mike @@ -339,133 +431,140 @@ public function getQuotetemplates($args=array()){ if ( ! empty( $newerThan ) && $newerThan > 0 ) $wheres['newerThan'] = array( 'zbsqt_created', '>=', '%d', $newerThan ); // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed - #} Is Tagged (expects 1 tag ID OR array) - /* - // catch 1 item arr - if (is_array($isTagged) && count($isTagged) == 1) $isTagged = $isTagged[0]; + #} Is Tagged (expects 1 tag ID OR array) + /* + // catch 1 item arr + if (is_array($isTagged) && count($isTagged) == 1) $isTagged = $isTagged[0]; + + if (!is_array($isTagged) && !empty($isTagged) && $isTagged > 0){ - if (!is_array($isTagged) && !empty($isTagged) && $isTagged > 0){ + // add where tagged + // 1 int: + $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quotetemplate.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_QUOTETEMPLATE,$isTagged)); - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quotetemplate.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_QUOTETEMPLATE,$isTagged)); + } else if (is_array($isTagged) && count($isTagged) > 0){ - } else if (is_array($isTagged) && count($isTagged) > 0){ + // foreach in array :) + $tagStr = ''; + foreach ($isTagged as $iTag){ + $i = (int)$iTag; + if ($i > 0){ - // foreach in array :) - $tagStr = ''; - foreach ($isTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + if ($tagStr !== '') $tagStr .','; + $tagStr .= $i; + } + } + if (!empty($tagStr)){ - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quotetemplate.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_QUOTETEMPLATE,$tagStr)); + $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quotetemplate.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_QUOTETEMPLATE,$tagStr)); - } + } - } - #} Is NOT Tagged (expects 1 tag ID OR array) + } + #} Is NOT Tagged (expects 1 tag ID OR array) - // catch 1 item arr - if (is_array($isNotTagged) && count($isNotTagged) == 1) $isNotTagged = $isNotTagged[0]; - - if (!is_array($isNotTagged) && !empty($isNotTagged) && $isNotTagged > 0){ + // catch 1 item arr + if (is_array($isNotTagged) && count($isNotTagged) == 1) $isNotTagged = $isNotTagged[0]; - // add where tagged - // 1 int: - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quotetemplate.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_QUOTETEMPLATE,$isNotTagged)); + if (!is_array($isNotTagged) && !empty($isNotTagged) && $isNotTagged > 0){ - } else if (is_array($isNotTagged) && count($isNotTagged) > 0){ + // add where tagged + // 1 int: + $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quotetemplate.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_QUOTETEMPLATE,$isNotTagged)); - // foreach in array :) - $tagStr = ''; - foreach ($isNotTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + } else if (is_array($isNotTagged) && count($isNotTagged) > 0){ - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quotetemplate.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_QUOTETEMPLATE,$tagStr)); + // foreach in array :) + $tagStr = ''; + foreach ($isNotTagged as $iTag){ + $i = (int)$iTag; + if ($i > 0){ - } + if ($tagStr !== '') $tagStr .','; + $tagStr .= $i; + } + } + if (!empty($tagStr)){ - } */ + $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quotetemplate.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_QUOTETEMPLATE,$tagStr)); - + } - #} ============ / WHERE =============== + } */ - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; + #} ============ / WHERE =============== - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} CHECK this + reset to default if faulty + if ( ! in_array( $whereCase, array( 'AND', 'OR' ) ) ) { + $whereCase = 'AND'; + } - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'quotetemplate'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params, $whereCase ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); - - try { + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'quotetemplate' ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Prep & run query - $queryObj = $this->prepare($query,$params); + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} Catch count + return if requested - if ($count) return $wpdb->get_var($queryObj); + try { - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - } catch (Exception $e){ + #} Catch count + return if requested + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } - #} General SQL Err - $this->catchSQLError($e); + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - } + } catch ( Exception $e ) { - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + #} General SQL Err + $this->catchSQLError( $e ); - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $resArr = $this->tidy_quotetemplate($resDataLine); //withCustomFields + } - // here we also grab this meta to see if is default - if ($checkDefaults) $resArr['default'] = $this->DAL()->meta(ZBS_TYPE_QUOTETEMPLATE,$resDataLine->ID,'zbsdefault',false); + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - /*if ($withTags){ + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_QUOTETEMPLATE,'objid'=>$resDataLine->ID)); + // tidy + $resArr = $this->tidy_quotetemplate( $resDataLine ); // withCustomFields - }*/ + // here we also grab this meta to see if is default + if ( $checkDefaults ) { + $resArr['default'] = $this->DAL()->meta( ZBS_TYPE_QUOTETEMPLATE, $resDataLine->ID, 'zbsdefault', false ); + } - $res[] = $resArr; + /* + if ($withTags){ - } - } + // add all tags lines + $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_QUOTETEMPLATE,'objid'=>$resDataLine->ID)); - return $res; - } + }*/ + $res[] = $resArr; + } + } + + return $res; + } /** * Returns a count of contacts (owned) @@ -475,717 +574,756 @@ public function getQuotetemplates($args=array()){ * * @return int count */ - public function getQuotetemplateCount($args=array()){ - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // Search/Filtering (leave as false to ignore) - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTETEMPLATE), // this'll let you not-check the owner of obj - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - $whereArr = array(); - - //if ($withStatus !== false && !empty($withStatus)) $whereArr['status'] = array('zbsqt_status','=','%s',$withStatus); - - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_QUOTETEMPLATE, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - - - return 0; - - } - - /** - * adds or updates a quotetemplate object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateQuotetemplate($args=array()){ - - global $ZBSCRM_t,$wpdb,$zbs; - - #} Retrieve any cf - //$customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_QUOTETEMPLATE)); - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - 'owner' => -1, - - // fields (directly) - 'data' => array( - - 'title' => '', - 'value' => '', - 'date_str' => '', - 'date' => '', - 'content' => '', - 'notes' => '', - 'currency' => '', - - // Note Custom fields may be passed here, but will not have defaults so check isset() - - // allow this to be set for MS sync etc. - 'created' => -1, - 'lastupdated' => '', - - ), - - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) - // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) - - // this function as DAL1 func did. - 'extraMeta' => -1, - 'automatorPassthrough' => -1, - 'fallBackLog' => -1, - - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newQuotetemplate (because is migrating, not creating new :) this was -1 before - - 'do_not_update_blanks' => false // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - - #} =========== / LOAD ARGS ============ - - #} ========== CHECK FIELDS ============ - - $id = (int)$id; - - // here we check that the potential owner CAN even own - if ($owner > 0 && !user_can($owner,'admin_zerobs_usr')) $owner = -1; - - // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } - - - if (is_array($limitedFields)){ - - // LIMITED UPDATE (only a few fields.) - if (!is_array($limitedFields) || count ($limitedFields) <= 0) return false; - // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; - - } else { - - // NORMAL, FULL UPDATE - - } - - #} ========= / CHECK FIELDS =========== - - - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - - // either ext source + setting, or set by the func call - if ($do_not_update_blanks){ - - // this setting says 'don't override filled-out data with blanks' - // so here we check through any passed blanks + convert to limitedFields - // only matters if $id is set (there is somt to update not add - if (isset($id) && !empty($id) && $id > 0){ - - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_quotetemplate($data); - //unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue - //unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - - $origData = $data; //$data = array(); - $limitedData = array(); // array(array('key'=>'zbsqt_x','val'=>y,'type'=>'%s')) - - // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) - // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates - foreach ($dbData as $k => $v){ - - $intV = (int)$v; + public function getQuotetemplateCount( $args = array() ) { - // only add if valuenot empty - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ - - // add to update arr - $limitedData[] = array( - 'key' => 'zbsqt_'.$k, // we have to add zbsqt_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbsqt_'.$k) - ); + #} ============ LOAD ARGS ============= + $defaultArgs = array( - // add to remade $data for post-update updates - $data[$k] = $v; + // Search/Filtering (leave as false to ignore) - } + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTETEMPLATE ), // this'll let you not-check the owner of obj - } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // copy over - $limitedFields = $limitedData; + $whereArr = array(); - } // / if ID + // if ($withStatus !== false && !empty($withStatus)) $whereArr['status'] = array('zbsqt_status','=','%s',$withStatus); - } // / if do_not_update_blanks + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_QUOTETEMPLATE, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); - #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== + return 0; + } + /** + * adds or updates a quotetemplate object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateQuotetemplate( $args = array() ) { - #} ========= BUILD DATA =========== + global $ZBSCRM_t, $wpdb, $zbs; - $update = false; $dataArr = array(); $typeArr = array(); + #} Retrieve any cf + // $customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_QUOTETEMPLATE)); - if (is_array($limitedFields)){ + #} ============ LOAD ARGS ============= + $defaultArgs = array( - // LIMITED FIELDS - $update = true; + 'id' => -1, + 'owner' => -1, - // cycle through - foreach ($limitedFields as $field){ + // fields (directly) + 'data' => array( - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } + 'title' => '', + 'value' => '', + 'date_str' => '', + 'date' => '', + 'content' => '', + 'notes' => '', + 'currency' => '', - } + // Note Custom fields may be passed here, but will not have defaults so check isset() - // add update time - if (!isset($dataArr['zbsqt_lastupdated'])){ $dataArr['zbsqt_lastupdated'] = time(); $typeArr[] = '%d'; } + // allow this to be set for MS sync etc. + 'created' => -1, + 'lastupdated' => '', - } else { + ), - // FULL UPDATE/INSERT + 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) - // UPDATE - $dataArr = array( + // this function as DAL1 func did. + 'extraMeta' => -1, + 'automatorPassthrough' => -1, + 'fallBackLog' => -1, - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newQuotetemplate (because is migrating, not creating new :) this was -1 before - - 'zbsqt_title' => $data['title'], - 'zbsqt_value' => $data['value'], - 'zbsqt_date_str' => $data['date_str'], - 'zbsqt_date' => $data['date'], - 'zbsqt_content' => $data['content'], - 'zbsqt_notes' => $data['notes'], - 'zbsqt_currency' => $data['currency'], - 'zbsqt_lastupdated' => time(), + 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) - ); + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner + #} =========== / LOAD ARGS ============ - - '%s', - '%s', - '%s', - '%d', - '%s', - '%s', - '%s', - '%d', + #} ========== CHECK FIELDS ============ - ); + $id = (int) $id; - if (!empty($id) && $id > 0){ + // here we check that the potential owner CAN even own + if ( $owner > 0 && ! user_can( $owner, 'admin_zerobs_usr' ) ) { + $owner = -1; + } - // is update - $update = true; + // if owner = -1, add current + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); } - } else { + if ( is_array( $limitedFields ) ) { - // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $typeArr[] = '%d'; - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbsqt_created'] = $data['created'];$typeArr[] = '%d'; - } else { - $dataArr['zbsqt_created'] = time(); $typeArr[] = '%d'; - } + // LIMITED UPDATE (only a few fields.) + if ( ! is_array( $limitedFields ) || count( $limitedFields ) <= 0 ) { + return false; + } + // REQ. ID too (can only update) + if ( empty( $id ) || $id <= 0 ) { + return false; + } + } else { - } + // NORMAL, FULL UPDATE - } + } - #} ========= / BUILD DATA =========== + #} ========= / CHECK FIELDS =========== - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - // if we're passing limitedFields we skip these, for now - // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ + // either ext source + setting, or set by the func call + if ( $do_not_update_blanks ) { - // verify uniques - if (!$this->verifyUniqueValues($data,$id)) return false; // / fails unique field verify + // this setting says 'don't override filled-out data with blanks' + // so here we check through any passed blanks + convert to limitedFields + // only matters if $id is set (there is somt to update not add + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - // verify not_empty - if (!$this->verifyNonEmptyValues($data)) return false; // / fails empty field verify + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_quotetemplate( $data ); + // unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue + // unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - } + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbsqt_x','val'=>y,'type'=>'%s')) - // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks($dataArr); - - #} ========= / CHECK force_uniques & not_empty ================ - #} ============================================================ - - #} Check if ID present - if ($update){ - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['quotetemplates'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ - - - // if passing limitedFields instead of data, we ignore the following - // this doesn't work, because data is in args default as arr - //if (isset($data) && is_array($data)){ - // so... - if (!isset($limitedFields) || !is_array($limitedFields) || $limitedFields == -1){ - /* - // tag work? - if (isset($data['tags']) && is_array($data['tags'])) $this->addUpdateQuotetemplateTags(array('id'=>$id,'tagIDs'=>$data['tags'])); - - // Custom fields? - - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ - - // any? - if (isset($data[$cK])){ + // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) + // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates + foreach ( $dbData as $k => $v ) { - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_QUOTETEMPLATE, - 'objid' => $id, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + $intV = (int) $v; - } - - } + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { - // / Custom Fields + // add to update arr + $limitedData[] = array( + 'key' => 'zbsqt_' . $k, // we have to add zbsqt_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbsqt_' . $k ), + ); + + // add to remade $data for post-update updates + $data[ $k ] = $v; + + } + } + + // copy over + $limitedFields = $limitedData; + + } // / if ID + + } // / if do_not_update_blanks + + #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== + + #} ========= BUILD DATA =========== + + $update = false; + $dataArr = array(); + $typeArr = array(); + + if ( is_array( $limitedFields ) ) { + + // LIMITED FIELDS + $update = true; - */ + // cycle through + foreach ( $limitedFields as $field ) { - } // / if $data + // some weird case where getting empties, so added check + if ( ! empty( $field['key'] ) ) { + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } + } - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; + // add update time + if ( ! isset( $dataArr['zbsqt_lastupdated'] ) ) { + $dataArr['zbsqt_lastupdated'] = time(); + $typeArr[] = '%d'; } + } else { + + // FULL UPDATE/INSERT + + // UPDATE + $dataArr = array( + + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, + + 'zbsqt_title' => $data['title'], + 'zbsqt_value' => $data['value'], + 'zbsqt_date_str' => $data['date_str'], + 'zbsqt_date' => $data['date'], + 'zbsqt_content' => $data['content'], + 'zbsqt_notes' => $data['notes'], + 'zbsqt_currency' => $data['currency'], + 'zbsqt_lastupdated' => time(), + + ); + + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner + + '%s', + '%s', + '%s', + '%d', + '%s', + '%s', + '%s', + '%d', + + ); + + if ( ! empty( $id ) && $id > 0 ) { + + // is update + $update = true; + + } else { + + // INSERT (get's few extra :D) + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbsqt_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbsqt_created'] = time(); + $typeArr[] = '%d'; + } + } + } + + #} ========= / BUILD DATA =========== + + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== + + // if we're passing limitedFields we skip these, for now + // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 + if ( ! is_array( $limitedFields ) ) { + + // verify uniques + if ( ! $this->verifyUniqueValues( $data, $id ) ) { + return false; // / fails unique field verify + } + + // verify not_empty + if ( ! $this->verifyNonEmptyValues( $data ) ) { + return false; // / fails empty field verify + } + } + + // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections + $dataArr = $this->wpdbChecks( $dataArr ); + + #} ========= / CHECK force_uniques & not_empty ================ + #} ============================================================ + + #} Check if ID present + if ( $update ) { + + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['quotetemplates'], + $dataArr, + array( // where + 'ID' => $id, + ), + $typeArr, + array( // where data types + '%d', + ) + ) !== false ) { + + // if passing limitedFields instead of data, we ignore the following + // this doesn't work, because data is in args default as arr + // if (isset($data) && is_array($data)){ + // so... + if ( ! isset( $limitedFields ) || ! is_array( $limitedFields ) || $limitedFields == -1 ) { + /* + // tag work? + if (isset($data['tags']) && is_array($data['tags'])) $this->addUpdateQuotetemplateTags(array('id'=>$id,'tagIDs'=>$data['tags'])); + + // Custom fields? + + #} Cycle through + add/update if set + if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + + // any? + if (isset($data[$cK])){ + + // add update + $cfID = $this->DAL()->addUpdateCustomField(array( + 'data' => array( + 'objtype' => ZBS_TYPE_QUOTETEMPLATE, + 'objid' => $id, + 'objkey' => $cK, + 'objval' => $data[$cK] + ))); + + } + + } + + // / Custom Fields + + */ + + } // / if $data + + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $confirmedExtraMeta = array(); - - foreach ($extraMeta as $k => $v){ + $confirmedExtraMeta = array(); - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + foreach ( $extraMeta as $k => $v ) { - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_QUOTETEMPLATE,$id,'extra_'.$cleanKey,$v); + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_QUOTETEMPLATE, $id, 'extra_' . $cleanKey, $v ); - } + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - } + } + } + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // UPDATING CONTACT + if ( ! $silentInsert ) { - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ + // IA General quotetemplate update (2.87+) + zeroBSCRM_FireInternalAutomator( + 'quotetemplate.update', + array( + 'id' => $id, + 'againstid' => $id, + 'data' => $dataArr, + ) + ); - // IA General quotetemplate update (2.87+) - zeroBSCRM_FireInternalAutomator('quotetemplate.update',array( - 'id'=>$id, - 'againstid' => $id, - 'data'=> $dataArr - )); + } - } + // Successfully updated - Return id + return $id; - - // Successfully updated - Return id - return $id; + } else { - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - // FAILED update - return false; + // FAILED update + return false; - } + } + } else { - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['quotetemplates'], - $dataArr, - $typeArr ) > 0){ + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['quotetemplates'], + $dataArr, + $typeArr + ) > 0 ) { - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - /* - // tag work? - if (isset($data['tags']) && is_array($data['tags'])) $this->addUpdateQuotetemplateTags(array('id'=>$newID,'tagIDs'=>$data['tags'])); + /* + // tag work? + if (isset($data['tags']) && is_array($data['tags'])) $this->addUpdateQuotetemplateTags(array('id'=>$newID,'tagIDs'=>$data['tags'])); - // Custom fields? + // Custom fields? - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + #} Cycle through + add/update if set + if (is_array($customFields)) foreach ($customFields as $cK => $cF){ - // any? - if (isset($data[$cK])){ + // any? + if (isset($data[$cK])){ - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_QUOTETEMPLATE, - 'objid' => $newID, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + // add update + $cfID = $this->DAL()->addUpdateCustomField(array( + 'data' => array( + 'objtype' => ZBS_TYPE_QUOTETEMPLATE, + 'objid' => $newID, + 'objkey' => $cK, + 'objval' => $data[$cK] + ))); - } + } - } + } - // / Custom Fields + // / Custom Fields - */ + */ - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $confirmedExtraMeta = array(); - - foreach ($extraMeta as $k => $v){ - - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); - - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_QUOTETEMPLATE,$id,'extra_'.$cleanKey,$v); - - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; - - } - - } + $confirmedExtraMeta = array(); + foreach ( $extraMeta as $k => $v ) { + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT - if (!$silentInsert){ + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_QUOTETEMPLATE, $id, 'extra_' . $cleanKey, $v ); - #} Add to automator - zeroBSCRM_FireInternalAutomator('quotetemplate.new',array( - 'id'=>$newID, - 'data'=>$dataArr, - //'extsource'=>array(), - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - } - - return $newID; + } + } - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // NEW CONTACT + if ( ! $silentInsert ) { - #} Failed to Insert - return false; + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'quotetemplate.new', + array( + 'id' => $newID, + 'data' => $dataArr, + // 'extsource'=>array(), + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); - } + } - } + return $newID; - return false; + } else { - } + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); - /** - * adds or updates a quotetemplate's tags - * ... this is really just a wrapper for addUpdateObjectTags - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - /* - public function addUpdateQuotetemplateTags($args=array()){ + #} Failed to Insert + return false; - global $ZBSCRM_t,$wpdb; + } + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - - // EITHER of the following: - 'tagIDs' => -1, - 'tags' => -1, - - 'mode' => 'append' - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} ========== CHECK FIELDS ============ - - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; + return false; + } - #} ========= / CHECK FIELDS =========== + /** + * adds or updates a quotetemplate's tags + * ... this is really just a wrapper for addUpdateObjectTags + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + /* + public function addUpdateQuotetemplateTags($args=array()){ - return $this->DAL()->addUpdateObjectTags(array( - 'objtype' =>ZBS_TYPE_QUOTETEMPLATE, - 'objid' =>$id, - 'tags' =>$tags, - 'tagIDs' =>$tagIDs, - 'mode' =>$mode)); + global $ZBSCRM_t,$wpdb; - } */ + #} ============ LOAD ARGS ============= + $defaultArgs = array( + 'id' => -1, + // EITHER of the following: + 'tagIDs' => -1, + 'tags' => -1, - /** - * deletes a quotetemplate object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteQuotetemplate($args=array()){ + 'mode' => 'append' - global $ZBSCRM_t,$wpdb,$zbs; + ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } + #} =========== / LOAD ARGS ============ - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ========== CHECK FIELDS ============ - 'id' => -1, - 'saveOrphans' => true + // check id + $id = (int)$id; if (empty($id) || $id <= 0) return false; - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} ========= / CHECK FIELDS =========== - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ + return $this->DAL()->addUpdateObjectTags(array( + 'objtype' =>ZBS_TYPE_QUOTETEMPLATE, + 'objid' =>$id, + 'tags' =>$tags, + 'tagIDs' =>$tagIDs, + 'mode' =>$mode)); + } */ - } + /** + * deletes a quotetemplate object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteQuotetemplate( $args = array() ) { - return zeroBSCRM_db2_deleteGeneric($id,'quotetemplates'); + global $ZBSCRM_t, $wpdb, $zbs; - } + #} ============ LOAD ARGS ============= + $defaultArgs = array( - return false; + 'id' => -1, + 'saveOrphans' => true, - } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ + + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + + // delete orphans? + if ( $saveOrphans === false ) { + + } + + return zeroBSCRM_db2_deleteGeneric( $id, 'quotetemplates' ); + + } + + return false; + } - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array quotetemplate (clean obj) - */ - private function tidy_quotetemplate($obj=false,$withCustomFields=false){ + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array quotetemplate (clean obj) + */ + private function tidy_quotetemplate( $obj = false, $withCustomFields = false ) { global $zbs; - $res = false; - - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = $obj->zbs_owner; - + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = $obj->zbs_owner; $res['title'] = wp_kses( html_entity_decode( $obj->zbsqt_title, ENT_QUOTES, 'UTF-8' ), $zbs->acceptable_restricted_html ); - $res['value'] = $this->stripSlashes($obj->zbsqt_value); - $res['date_str'] = $this->stripSlashes($obj->zbsqt_date_str); - $res['date'] = (int)$obj->zbsqt_date; - $res['date_date'] = (isset($obj->zbsqt_date) && $obj->zbsqt_date > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsqt_date) : false; - $res['content'] = $this->stripSlashes($obj->zbsqt_content); + $res['value'] = $this->stripSlashes( $obj->zbsqt_value ); + $res['date_str'] = $this->stripSlashes( $obj->zbsqt_date_str ); + $res['date'] = (int) $obj->zbsqt_date; + $res['date_date'] = ( isset( $obj->zbsqt_date ) && $obj->zbsqt_date > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbsqt_date ) : false; + $res['content'] = $this->stripSlashes( $obj->zbsqt_content ); $res['notes'] = wp_kses( html_entity_decode( $obj->zbsqt_notes, ENT_QUOTES, 'UTF-8' ), $zbs->acceptable_restricted_html ); - $res['currency'] = $this->stripSlashes($obj->zbsqt_currency); - $res['created'] = (int)$obj->zbsqt_created; - $res['created_date'] = (isset($obj->zbsqt_created) && $obj->zbsqt_created > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsqt_created) : false; - $res['lastupdated'] = (int)$obj->zbsqt_lastupdated; - $res['lastupdated_date'] = (isset($obj->zbsqt_lastupdated) && $obj->zbsqt_lastupdated > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbsqt_lastupdated) : false; - - // custom fields - tidy any that are present: - if ($withCustomFields) $res = $this->tidyAddCustomFields(ZBS_TYPE_QUOTETEMPLATE,$obj,$res,false); - - } - - - return $res; - - - } - - - /** - * Wrapper, use $this->getQuotetemplateMeta($contactID,$key) for easy retrieval of singular quotetemplate - * Simplifies $this->getMeta - * - * @param int objtype - * @param int objid - * @param string key - * - * @return array quotetemplate meta result - */ - public function getQuotetemplateMeta($id=-1,$key='',$default=false){ - - global $zbs; - - if (!empty($key)){ + $res['currency'] = $this->stripSlashes( $obj->zbsqt_currency ); + $res['created'] = (int) $obj->zbsqt_created; + $res['created_date'] = ( isset( $obj->zbsqt_created ) && $obj->zbsqt_created > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbsqt_created ) : false; + $res['lastupdated'] = (int) $obj->zbsqt_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbsqt_lastupdated ) && $obj->zbsqt_lastupdated > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbsqt_lastupdated ) : false; + + // custom fields - tidy any that are present: + if ( $withCustomFields ) { + $res = $this->tidyAddCustomFields( ZBS_TYPE_QUOTETEMPLATE, $obj, $res, false ); + } + } + + return $res; + } - return $this->DAL()->getMeta(array( + /** + * Wrapper, use $this->getQuotetemplateMeta($contactID,$key) for easy retrieval of singular quotetemplate + * Simplifies $this->getMeta + * + * @param int objtype + * @param int objid + * @param string key + * + * @return array quotetemplate meta result + */ + public function getQuotetemplateMeta( $id = -1, $key = '', $default = false ) { - 'objtype' => ZBS_TYPE_QUOTETEMPLATE, - 'objid' => $id, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default, - 'ignoreowner' => true // for now !! + global $zbs; - )); + if ( ! empty( $key ) ) { - } + return $this->DAL()->getMeta( + array( - return $default; - } + 'objtype' => ZBS_TYPE_QUOTETEMPLATE, + 'objid' => $id, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, + 'ignoreowner' => true, // for now !! + ) + ); - - /** - * Returns an ownerid against a quotetemplate - * - * @param int id quotetemplate ID - * - * @return int quotetemplate owner id - */ - public function getQuotetemplateOwner($id=-1){ + } - global $zbs; + return $default; + } - $id = (int)$id; + /** + * Returns an ownerid against a quotetemplate + * + * @param int id quotetemplate ID + * + * @return int quotetemplate owner id + */ + public function getQuotetemplateOwner( $id = -1 ) { - if ($id > 0){ + global $zbs; - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_QUOTETEMPLATE, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); + $id = (int) $id; - } + if ( $id > 0 ) { - return false; - - } + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTETEMPLATE, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); + } - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * This does so based on the objectModel! - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - private function db_ready_quotetemplate($obj=false){ + return false; + } - // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * This does so based on the objectModel! + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + private function db_ready_quotetemplate( $obj = false ) { - } + // use the generic? (override here if necessary) + return $this->db_ready_obj( $obj ); + } - /** - * Takes full object and makes a "list view" boiled down version - * Used to generate listview objs - * - * @param array $obj (clean obj) - * - * @return array (listview ready obj) - */ - public function listViewObj($quotetemplate=false,$columnsRequired=array()){ + /** + * Takes full object and makes a "list view" boiled down version + * Used to generate listview objs + * + * @param array $obj (clean obj) + * + * @return array (listview ready obj) + */ + public function listViewObj( $quotetemplate = false, $columnsRequired = array() ) { - if (is_array($quotetemplate) && isset($quotetemplate['id'])){ + if ( is_array( $quotetemplate ) && isset( $quotetemplate['id'] ) ) { - $resArr = $quotetemplate; - - return $resArr; + $resArr = $quotetemplate; - } + return $resArr; - return false; + } - } + return false; + } - // =========== / QUOTETEMPLATE ======================================================= - // =============================================================================== + // =========== / QUOTETEMPLATE ======================================================= + // =============================================================================== } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Segments.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Segments.php index db6cf9ef8641..4cbd9c16bb60 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Segments.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Segments.php @@ -1,5 +1,6 @@ -> Segments -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Segments + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_segments extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_SEGMENT; - protected $objectModel = array( - - // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), - - // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner' => array('fieldname' => 'zbs_owner', 'format' => 'int'), - - // other fields - 'name' => array('fieldname' => 'zbsseg_name', 'format' => 'str'), - 'slug' => array('fieldname' => 'zbsseg_slug', 'format' => 'str'), - 'matchtype' => array('fieldname' => 'zbsseg_matchtype', 'format' => 'str'), - 'created' => array('fieldname' => 'zbsseg_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsseg_lastupdated', 'format' => 'uts'), - 'compilecount' => array('fieldname' => 'zbsseg_compilecount', 'format' => 'int'), - 'lastcompiled' => array('fieldname' => 'zbsseg_lastcompiled', 'format' => 'uts'), - - ); - - - function __construct($args=array()) { - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - - } - - - // =============================================================================== - // =========== SEGMENTS ======================================================= - - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ - - return $this->getSegment($ID); - - } - - // This was actually written pre DAL2 and so still has some legacy layout of func - // etc. To be slowly refined if needed. - - - /** - * get a segment (header line) - */ - public function getSegment($segmentID=-1,$withConditions=false,$checkOwnershipID=false){ - - if ($segmentID > 0){ - - global $ZBSCRM_t,$wpdb; - - $additionalWHERE = ''; $queryVars = array($segmentID); - - // check ownership - // THIS ShoULD BE STANDARDISED THROUGHOUT DAL (ON DB2) - // $checkOwnershipID = ID = check against that ID - // $checkOwnershipID = true = check against get_current_user_id - // $checkOwnershipID = false = do not check - - if ($checkOwnershipID === true){ - - $segmentOwner = get_current_user_id(); - - } elseif ($checkOwnershipID > 0){ - - $segmentOwner = (int)$checkOwnershipID; - - } // else is false, don't test - - if (isset($segmentOwner)){ - - // add check - $additionalWHERE = 'AND zbs_owner = %d'; - $queryVars[] = $segmentOwner; - - } - - - $potentialSegment = $wpdb->get_row( $this->prepare("SELECT * FROM ".$ZBSCRM_t['segments']." WHERE ID = %d ".$additionalWHERE."ORDER BY ID ASC LIMIT 0,1",$queryVars), OBJECT ); - - if (isset($potentialSegment) && isset($potentialSegment->ID)){ + protected $objectType = ZBS_TYPE_SEGMENT; + protected $objectModel = array( + + // ID + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), + + // site + team generics + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), + + // other fields + 'name' => array( + 'fieldname' => 'zbsseg_name', + 'format' => 'str', + ), + 'slug' => array( + 'fieldname' => 'zbsseg_slug', + 'format' => 'str', + ), + 'matchtype' => array( + 'fieldname' => 'zbsseg_matchtype', + 'format' => 'str', + ), + 'created' => array( + 'fieldname' => 'zbsseg_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsseg_lastupdated', + 'format' => 'uts', + ), + 'compilecount' => array( + 'fieldname' => 'zbsseg_compilecount', + 'format' => 'int', + ), + 'lastcompiled' => array( + 'fieldname' => 'zbsseg_lastcompiled', + 'format' => 'uts', + ), + + ); + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + } - #} Retrieved :) fill + return - - // tidy - $segment = $this->tidy_segment($potentialSegment); + // =============================================================================== + // =========== SEGMENTS ======================================================= - if ($withConditions) { + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { - $segment['conditions'] = $this->getSegmentConditions($segment['id']); + return $this->getSegment( $ID ); + } - } + // This was actually written pre DAL2 and so still has some legacy layout of func + // etc. To be slowly refined if needed. - // this catches any 'broken' state segments. - // ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack - $error_string = $this->segment_error( $segment['id'] ); - if ( !empty( $error_string ) ){ - $segment['error'] = zeroBSCRM_textExpose( $error_string ); - } + /** + * get a segment (header line) + */ + public function getSegment( $segmentID = -1, $withConditions = false, $checkOwnershipID = false ) { - return $segment; - } + if ( $segmentID > 0 ) { - } + global $ZBSCRM_t, $wpdb; - return false; - - } + $additionalWHERE = ''; + $queryVars = array( $segmentID ); - /** - * get Sements Pass -1 for $perPage and $page and this'll return ALL - */ - public function getSegments($ownerID=-1,$perPage=10,$page=0,$withConditions=false,$searchPhrase='',$inArr='',$sortByField='',$sortOrder='DESC'){ + // check ownership + // THIS ShoULD BE STANDARDISED THROUGHOUT DAL (ON DB2) + // $checkOwnershipID = ID = check against that ID + // $checkOwnershipID = true = check against get_current_user_id + // $checkOwnershipID = false = do not check - global $zbs,$ZBSCRM_t,$wpdb; + if ( $checkOwnershipID === true ) { - $segments = false; + $segmentOwner = get_current_user_id(); - // build query - $sql = "SELECT * FROM ".$ZBSCRM_t['segments']; - $wheres = array(); - $params = array(); - $orderByStr = ''; + } elseif ( $checkOwnershipID > 0 ) { - // Owner + $segmentOwner = (int) $checkOwnershipID; - // escape (all) - if ($ownerID != -99){ + } // else is false, don't test - if ($ownerID === -1) $ownerID = get_current_user_id(); + if ( isset( $segmentOwner ) ) { - if (!empty($ownerID)) $wheres['zbs_owner'] = array('=',$ownerID,'%d'); + // add check + $additionalWHERE = 'AND zbs_owner = %d'; + $queryVars[] = $segmentOwner; - } + } + $potentialSegment = $wpdb->get_row( $this->prepare( 'SELECT * FROM ' . $ZBSCRM_t['segments'] . ' WHERE ID = %d ' . $additionalWHERE . 'ORDER BY ID ASC LIMIT 0,1', $queryVars ), OBJECT ); - // search phrase - if (!empty($searchPhrase)){ + if ( isset( $potentialSegment ) && isset( $potentialSegment->ID ) ) { - $wheres['zbsseg_name'] = array('LIKE','%'.$searchPhrase.'%','%s'); + #} Retrieved :) fill + return - } + // tidy + $segment = $this->tidy_segment( $potentialSegment ); - // in array - if (is_array($inArr) && count($inArr) > 0){ + if ( $withConditions ) { - $wheres['ID'] = array('IN','('.implode(',', $inArr).')','%s'); + $segment['conditions'] = $this->getSegmentConditions( $segment['id'] ); - } + } - // add where's to SQL - // + - // feed in params - $whereStr = ''; - if (count($wheres) > 0) foreach ($wheres as $key => $whereArr) { + // this catches any 'broken' state segments. + // ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack + $error_string = $this->segment_error( $segment['id'] ); + if ( ! empty( $error_string ) ) { + $segment['error'] = zeroBSCRM_textExpose( $error_string ); + } - if (!empty($whereStr)) - $whereStr .= ' AND '; - else - $whereStr .= ' WHERE '; + return $segment; + } + } - // add in - NOTE: this is TRUSTING key + whereArr[0] - $whereStr .= $key.' '.$whereArr[0].' '.$whereArr[2]; + return false; + } - // feed in params - $params[] = $whereArr[1]; - } + /** + * get Sements Pass -1 for $perPage and $page and this'll return ALL + */ + public function getSegments( $ownerID = -1, $perPage = 10, $page = 0, $withConditions = false, $searchPhrase = '', $inArr = '', $sortByField = '', $sortOrder = 'DESC' ) { - // append to sql - $sql .= $whereStr; + global $zbs, $ZBSCRM_t, $wpdb; + $segments = false; + // build query + $sql = 'SELECT * FROM ' . $ZBSCRM_t['segments']; + $wheres = array(); + $params = array(); + $orderByStr = ''; - // sort by - if (!empty($sortByField)){ + // Owner - if (!in_array($sortOrder, array('DESC','ASC'))) $sortOrder = 'DESC'; + // escape (all) + if ( $ownerID != -99 ) { - // parametise order field as is unchecked - //$orderByStr = ' ORDER BY %s '.$sortOrder; - //$params[] = $sortByField; - $orderByStr = ' ORDER BY '.$sortByField.' '.$sortOrder; + if ( $ownerID === -1 ) { + $ownerID = get_current_user_id(); + } - } + if ( ! empty( $ownerID ) ) { + $wheres['zbs_owner'] = array( '=', $ownerID, '%d' ); + } + } + // search phrase + if ( ! empty( $searchPhrase ) ) { - // pagination - if ($page == -1 && $perPage == -1){ + $wheres['zbsseg_name'] = array( 'LIKE', '%' . $searchPhrase . '%', '%s' ); - // NO LIMITS :o + } + // in array + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { - } else { + $wheres['ID'] = array( 'IN', '(' . implode( ',', $inArr ) . ')', '%s' ); - // Because SQL USING zero indexed page numbers, we remove -1 here - // ... DO NOT change this without seeing usage of the function (e.g. list view) - which'll break - $page = (int)$page-1; - if ($page < 0) $page = 0; + } - // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $orderByStr .= sprintf( ' LIMIT %d, %d ', (int) $page * (int) $perPage, (int) $perPage ); - } + // add where's to SQL + // + + // feed in params + $whereStr = ''; + if ( count( $wheres ) > 0 ) { + foreach ( $wheres as $key => $whereArr ) { + + if ( ! empty( $whereStr ) ) { + $whereStr .= ' AND '; + } else { + $whereStr .= ' WHERE '; + } - // append to sql - $sql .= $orderByStr; + // add in - NOTE: this is TRUSTING key + whereArr[0] + $whereStr .= $key . ' ' . $whereArr[0] . ' ' . $whereArr[2]; - $query = $this->prepare($sql,$params); + // feed in params + $params[] = $whereArr[1]; + } + } - try { + // append to sql + $sql .= $whereStr; - $potentialSegments = $wpdb->get_results( $query, OBJECT ); + // sort by + if ( ! empty( $sortByField ) ) { - } catch (Exception $e){ + if ( ! in_array( $sortOrder, array( 'DESC', 'ASC' ) ) ) { + $sortOrder = 'DESC'; + } - // error with sql :/ for now nothin + // parametise order field as is unchecked + // $orderByStr = ' ORDER BY %s '.$sortOrder; + // $params[] = $sortByField; + $orderByStr = ' ORDER BY ' . $sortByField . ' ' . $sortOrder; - } + } - if (isset($potentialSegments) && is_array($potentialSegments)) $segments = $potentialSegments; + // pagination + if ( $page == -1 && $perPage == -1 ) { - // TIDY - $res = array(); - if (count($segments) > 0) foreach ($segments as $segment) { + // NO LIMITS :o - // tidy - $resArr = $this->tidy_segment($segment); + } else { - // TO ADD to query / here withConditions - // TODO: REFACTOR into query? More efficient? - if ($withConditions) $resArr['conditions'] = $this->getSegmentConditions($segment->ID); + // Because SQL USING zero indexed page numbers, we remove -1 here + // ... DO NOT change this without seeing usage of the function (e.g. list view) - which'll break + $page = (int) $page - 1; + if ( $page < 0 ) { + $page = 0; + } - // this catches any 'broken' state segments. - // ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack - $error_string = $this->segment_error( $segment->ID ); - if ( !empty( $error_string ) ){ - $resArr['error'] = zeroBSCRM_textExpose( $error_string ); - } - - $res[] = $resArr; + // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $orderByStr .= sprintf( ' LIMIT %d, %d ', (int) $page * (int) $perPage, (int) $perPage ); + } - } + // append to sql + $sql .= $orderByStr; - return $res; - - } + $query = $this->prepare( $sql, $params ); - // brutal simple temp func (should be a wrapper really. segments to tidy up post DAL2 other obj) - public function getSegmentCount(){ + try { - global $ZBSCRM_t,$wpdb; + $potentialSegments = $wpdb->get_results( $query, OBJECT ); - // build query - $sql = "SELECT COUNT(ID) FROM ".$ZBSCRM_t['segments']; + } catch ( Exception $e ) { - return $wpdb->get_var($sql); - - } + // error with sql :/ for now nothin + } - /** - * deletes a Segment object (and its conditions) - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteSegment($args=array()){ + if ( isset( $potentialSegments ) && is_array( $potentialSegments ) ) { + $segments = $potentialSegments; + } - global $ZBSCRM_t, $wpdb, $zbs; + // TIDY + $res = array(); + if ( count( $segments ) > 0 ) { + foreach ( $segments as $segment ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // tidy + $resArr = $this->tidy_segment( $segment ); - 'id' => -1, - 'saveOrphans' => -1 + // TO ADD to query / here withConditions + // TODO: REFACTOR into query? More efficient? + if ( $withConditions ) { + $resArr['conditions'] = $this->getSegmentConditions( $segment->ID ); + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + // this catches any 'broken' state segments. + // ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack + $error_string = $this->segment_error( $segment->ID ); + if ( ! empty( $error_string ) ) { + $resArr['error'] = zeroBSCRM_textExpose( $error_string ); + } - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { + $res[] = $resArr; - $segment = $this->getSegment( $id ); + } + } - $deleted = zeroBSCRM_db2_deleteGeneric($id,'segments'); + return $res; + } - // delete segment conditions? - // check $deleted? + // brutal simple temp func (should be a wrapper really. segments to tidy up post DAL2 other obj) + public function getSegmentCount() { - $del = $wpdb->delete( - $ZBSCRM_t['segmentsconditions'], - array( // where - 'zbscondition_segmentid' => $id - ), - array( - '%d' - ) - ); + global $ZBSCRM_t, $wpdb; - #} Add to automator - zeroBSCRM_FireInternalAutomator('segment.delete',array( - 'id' => $id, - 'saveOrphans' => $saveOrphans, - )); + // build query + $sql = 'SELECT COUNT(ID) FROM ' . $ZBSCRM_t['segments']; - return $del; + return $wpdb->get_var( $sql ); + } - } + /** + * deletes a Segment object (and its conditions) + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteSegment( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'saveOrphans' => -1, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - return false; + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - } + $segment = $this->getSegment( $id ); - /** - * tidys a segment - */ - public function tidy_segment($obj=false){ + $deleted = zeroBSCRM_db2_deleteGeneric( $id, 'segments' ); - $res = false; + // delete segment conditions? + // check $deleted? + $del = $wpdb->delete( + $ZBSCRM_t['segmentsconditions'], + array( // where + 'zbscondition_segmentid' => $id, + ), + array( + '%d', + ) + ); - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - - $res['name'] = $obj->zbsseg_name; - $res['slug'] = $obj->zbsseg_slug; - $res['matchtype'] = $obj->zbsseg_matchtype; + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'segment.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); - $res['created'] = $obj->zbsseg_created; - $res['lastupdated'] = $obj->zbsseg_lastupdated; - $res['compilecount'] = $obj->zbsseg_compilecount; - $res['lastcompiled'] = $obj->zbsseg_lastcompiled; + return $del; - // pretty date outputs for list viw - $res['createddate'] = zeroBSCRM_locale_utsToDate($obj->zbsseg_created); - $res['lastcompileddate'] = zeroBSCRM_locale_utsToDate($obj->zbsseg_lastcompiled); - } + } - return $res; + return false; + } - } + /** + * tidys a segment + */ + public function tidy_segment( $obj = false ) { - /** - * tidys a segment condition - */ - public function tidy_segment_condition($obj=false){ + $res = false; - $res = false; + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - - $res['segmentID'] = $obj->zbscondition_segmentid; - $res['type'] = $obj->zbscondition_type; - $res['operator'] = $obj->zbscondition_op; - $res['value'] = zeroBSCRM_textExpose($obj->zbscondition_val); - $res['value2'] = zeroBSCRM_textExpose($obj->zbscondition_val_secondary); + $res['name'] = $obj->zbsseg_name; + $res['slug'] = $obj->zbsseg_slug; + $res['matchtype'] = $obj->zbsseg_matchtype; - // applies any necessary conversions e.g. uts -> date - $res['valueconv'] = zeroBSCRM_segments_typeConversions($res['value'],$res['type'],$res['operator'],'out'); - $res['value2conv'] = zeroBSCRM_segments_typeConversions($res['value2'],$res['type'],$res['operator'],'out'); + $res['created'] = $obj->zbsseg_created; + $res['lastupdated'] = $obj->zbsseg_lastupdated; + $res['compilecount'] = $obj->zbsseg_compilecount; + $res['lastcompiled'] = $obj->zbsseg_lastcompiled; - } + // pretty date outputs for list viw + $res['createddate'] = zeroBSCRM_locale_utsToDate( $obj->zbsseg_created ); + $res['lastcompileddate'] = zeroBSCRM_locale_utsToDate( $obj->zbsseg_lastcompiled ); + } - return $res; + return $res; + } - } + /** + * tidys a segment condition + */ + public function tidy_segment_condition( $obj = false ) { - - /** - * This is designed to mimic zeroBS_getSegments, but only to return a total count :) - */ - public function getSegmentsCountIncParams($ownerID=-1,$perPage=10,$page=0,$withConditions=false,$searchPhrase='',$inArr='',$sortByField='',$sortOrder='DESC'){ + $res = false; - global $zbs,$ZBSCRM_t,$wpdb; + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; - $segmentCount = false; + $res['segmentID'] = $obj->zbscondition_segmentid; + $res['type'] = $obj->zbscondition_type; + $res['operator'] = $obj->zbscondition_op; + $res['value'] = zeroBSCRM_textExpose( $obj->zbscondition_val ); + $res['value2'] = zeroBSCRM_textExpose( $obj->zbscondition_val_secondary ); - // build query - $sql = "SELECT COUNT(ID) segcount FROM ".$ZBSCRM_t['segments']; - $wheres = array(); - $params = array(); - $orderByStr = ''; + // applies any necessary conversions e.g. uts -> date + $res['valueconv'] = zeroBSCRM_segments_typeConversions( $res['value'], $res['type'], $res['operator'], 'out' ); + $res['value2conv'] = zeroBSCRM_segments_typeConversions( $res['value2'], $res['type'], $res['operator'], 'out' ); - // Owner + } - // escape (all) - if ($ownerID != -99){ + return $res; + } - if ($ownerID === -1) $ownerID = get_current_user_id(); + /** + * This is designed to mimic zeroBS_getSegments, but only to return a total count :) + */ + public function getSegmentsCountIncParams( $ownerID = -1, $perPage = 10, $page = 0, $withConditions = false, $searchPhrase = '', $inArr = '', $sortByField = '', $sortOrder = 'DESC' ) { - if (!empty($ownerID)) $wheres['zbs_owner'] = array('=',$ownerID,'%d'); + global $zbs, $ZBSCRM_t, $wpdb; - } + $segmentCount = false; + // build query + $sql = 'SELECT COUNT(ID) segcount FROM ' . $ZBSCRM_t['segments']; + $wheres = array(); + $params = array(); + $orderByStr = ''; - // search phrase - if (!empty($searchPhrase)){ + // Owner - $wheres['zbsseg_name'] = array('LIKE',$searchPhrase,'%s'); + // escape (all) + if ( $ownerID != -99 ) { - } + if ( $ownerID === -1 ) { + $ownerID = get_current_user_id(); + } - // in array - if (is_array($inArr) && count($inArr) > 0){ + if ( ! empty( $ownerID ) ) { + $wheres['zbs_owner'] = array( '=', $ownerID, '%d' ); + } + } - $wheres['ID'] = array('IN','('.implode(',', $inArr).')','%s'); + // search phrase + if ( ! empty( $searchPhrase ) ) { - } + $wheres['zbsseg_name'] = array( 'LIKE', $searchPhrase, '%s' ); - // add where's to SQL - // + - // feed in params - $whereStr = ''; - if (count($wheres) > 0) foreach ($wheres as $key => $whereArr) { + } - if (!empty($whereStr)) - $whereStr .= ' AND '; - else - $whereStr .= ' WHERE '; + // in array + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { - // add in - NOTE: this is TRUSTING key + whereArr[0] - $whereStr .= $key.' '.$whereArr[0].' '.$whereArr[2]; + $wheres['ID'] = array( 'IN', '(' . implode( ',', $inArr ) . ')', '%s' ); - // feed in params - $params[] = $whereArr[1]; - } + } - // append to sql - $sql .= $whereStr; + // add where's to SQL + // + + // feed in params + $whereStr = ''; + if ( count( $wheres ) > 0 ) { + foreach ( $wheres as $key => $whereArr ) { + + if ( ! empty( $whereStr ) ) { + $whereStr .= ' AND '; + } else { + $whereStr .= ' WHERE '; + } - $query = $this->prepare($sql,$params); + // add in - NOTE: this is TRUSTING key + whereArr[0] + $whereStr .= $key . ' ' . $whereArr[0] . ' ' . $whereArr[2]; - try { + // feed in params + $params[] = $whereArr[1]; + } + } - $potentialSegmentCount = $wpdb->get_row( $query, OBJECT ); + // append to sql + $sql .= $whereStr; - } catch (Exception $e){ + $query = $this->prepare( $sql, $params ); - // error with sql :/ for now nothin + try { - } + $potentialSegmentCount = $wpdb->get_row( $query, OBJECT ); - if (isset($potentialSegmentCount) && isset($potentialSegmentCount->segcount)) $segmentCount = $potentialSegmentCount->segcount; + } catch ( Exception $e ) { - return $segmentCount; - - } + // error with sql :/ for now nothin + } - /** - * builds a preview (top 5 + count) of a set of conditions which could be against a segment - * expects a filtered list of conditions (e.g. zeroBSCRM_segments_filterConditions if sent through POST) - * - * Throws @Segment_Condition_Exception - */ - public function previewSegment($conditions=array(),$matchType='all',$countOnly=false){ + if ( isset( $potentialSegmentCount ) && isset( $potentialSegmentCount->segcount ) ) { + $segmentCount = $potentialSegmentCount->segcount; + } - - // retrieve getContacts arguments from a list of segment conditions - $contactGetArgs = $this->segmentConditionsToArgs($conditions,$matchType); + return $segmentCount; + } - // add top 5 + count params - $contactGetArgs['sortByField'] = 'RAND()'; - $contactGetArgs['sortOrder'] = ''; - $contactGetArgs['page'] = 0; - $contactGetArgs['perPage'] = 5; - $contactGetArgs['ignoreowner'] = zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT); + /** + * builds a preview (top 5 + count) of a set of conditions which could be against a segment + * expects a filtered list of conditions (e.g. zeroBSCRM_segments_filterConditions if sent through POST) + * + * Throws @Segment_Condition_Exception + */ + public function previewSegment( $conditions = array(), $matchType = 'all', $countOnly = false ) { - // count ver - $countContactGetArgs = $contactGetArgs; - $countContactGetArgs['perPage'] = 100000; - $countContactGetArgs['count'] = true; + // retrieve getContacts arguments from a list of segment conditions + $contactGetArgs = $this->segmentConditionsToArgs( $conditions, $matchType ); - // count only - if ( $countOnly ) { - return $this->DAL()->contacts->getContacts($countContactGetArgs); - } + // add top 5 + count params + $contactGetArgs['sortByField'] = 'RAND()'; + $contactGetArgs['sortOrder'] = ''; + $contactGetArgs['page'] = 0; + $contactGetArgs['perPage'] = 5; + $contactGetArgs['ignoreowner'] = zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ); - // Retrieve - return array( - // DEBUG - //'conditions' => $conditions, // TEMP - remove this - //'args' => $contactGetArgs, // TEMP - remove this - 'count'=>$this->DAL()->contacts->getContacts($countContactGetArgs), - 'list'=>$this->DAL()->contacts->getContacts($contactGetArgs) - ); + // count ver + $countContactGetArgs = $contactGetArgs; + $countContactGetArgs['perPage'] = 100000; + $countContactGetArgs['count'] = true; - } + // count only + if ( $countOnly ) { + return $this->DAL()->contacts->getContacts( $countContactGetArgs ); + } + // Retrieve + return array( + // DEBUG + // 'conditions' => $conditions, // TEMP - remove this + // 'args' => $contactGetArgs, // TEMP - remove this + 'count' => $this->DAL()->contacts->getContacts( $countContactGetArgs ), + 'list' => $this->DAL()->contacts->getContacts( $contactGetArgs ), + ); + } - /** - * used by previewSegment and getSegmentAudience to build condition args - */ - public function segmentConditionsToArgs($conditions=array(),$matchType='all'){ + /** + * used by previewSegment and getSegmentAudience to build condition args + */ + public function segmentConditionsToArgs( $conditions = array(), $matchType = 'all' ) { - if (is_array($conditions) && count($conditions) > 0){ + if ( is_array( $conditions ) && count( $conditions ) > 0 ) { - $contactGetArgs = array(); - $conditionIndx = 0; // this allows multiple queries for SAME field (e.g. status = x or status = y) + $contactGetArgs = array(); + $conditionIndx = 0; // this allows multiple queries for SAME field (e.g. status = x or status = y) - // cycle through & add to contact request arr - foreach ($conditions as $condition){ + // cycle through & add to contact request arr + foreach ( $conditions as $condition ) { - $newArgs = $this->segmentConditionArgs($condition,$conditionIndx); $additionalWHERE = false; + $newArgs = $this->segmentConditionArgs( $condition, $conditionIndx ); + $additionalWHERE = false; - // legit? merge (must be recursive) - if (is_array($newArgs)) $contactGetArgs = array_merge_recursive($contactGetArgs,$newArgs); + // legit? merge (must be recursive) + if ( is_array( $newArgs ) ) { + $contactGetArgs = array_merge_recursive( $contactGetArgs, $newArgs ); + } - $conditionIndx++; + ++$conditionIndx; - } + } - // match type ALL is default, this switches to ANY - if ($matchType == 'one') $contactGetArgs['whereCase'] = 'OR'; + // match type ALL is default, this switches to ANY + if ( $matchType == 'one' ) { + $contactGetArgs['whereCase'] = 'OR'; + } - return $contactGetArgs; + return $contactGetArgs; - } + } - return array(); + return array(); + } - } - - /** - * get a segment (header line) - */ - public function getSegmentBySlug($segmentSlug=-1,$withConditions=false,$checkOwnershipID=false){ + /** + * get a segment (header line) + */ + public function getSegmentBySlug( $segmentSlug = -1, $withConditions = false, $checkOwnershipID = false ) { - if (!empty($segmentSlug)){ - - global $ZBSCRM_t,$wpdb; + if ( ! empty( $segmentSlug ) ) { - $additionalWHERE = ''; $queryVars = array($segmentSlug); + global $ZBSCRM_t, $wpdb; - // check ownership - // THIS ShoULD BE STANDARDISED THROUGHOUT DAL (ON DB2) - // $checkOwnershipID = ID = check against that ID - // $checkOwnershipID = true = check against get_current_user_id - // $checkOwnershipID = false = do not check - - if ($checkOwnershipID === true){ + $additionalWHERE = ''; + $queryVars = array( $segmentSlug ); - $segmentOwner = get_current_user_id(); + // check ownership + // THIS ShoULD BE STANDARDISED THROUGHOUT DAL (ON DB2) + // $checkOwnershipID = ID = check against that ID + // $checkOwnershipID = true = check against get_current_user_id + // $checkOwnershipID = false = do not check - } elseif ($checkOwnershipID > 0){ + if ( $checkOwnershipID === true ) { - $segmentOwner = (int)$checkOwnershipID; + $segmentOwner = get_current_user_id(); - } // else is false, don't test + } elseif ( $checkOwnershipID > 0 ) { - if (isset($segmentOwner)){ + $segmentOwner = (int) $checkOwnershipID; - // add check - $additionalWHERE = 'AND zbs_owner = %d'; - $queryVars[] = $segmentOwner; + } // else is false, don't test - } - + if ( isset( $segmentOwner ) ) { - $potentialSegment = $wpdb->get_row( $this->prepare("SELECT * FROM ".$ZBSCRM_t['segments']." WHERE zbsseg_slug = %s ".$additionalWHERE."ORDER BY ID ASC LIMIT 0,1",$queryVars), OBJECT ); + // add check + $additionalWHERE = 'AND zbs_owner = %d'; + $queryVars[] = $segmentOwner; - if (isset($potentialSegment) && isset($potentialSegment->ID)){ + } - #} Retrieved :) fill + return - - // tidy - $segment = $this->tidy_segment($potentialSegment); + $potentialSegment = $wpdb->get_row( $this->prepare( 'SELECT * FROM ' . $ZBSCRM_t['segments'] . ' WHERE zbsseg_slug = %s ' . $additionalWHERE . 'ORDER BY ID ASC LIMIT 0,1', $queryVars ), OBJECT ); - if ($withConditions) { + if ( isset( $potentialSegment ) && isset( $potentialSegment->ID ) ) { - $segment['conditions'] = $this->getSegmentConditions($segment['id']); + #} Retrieved :) fill + return - } + // tidy + $segment = $this->tidy_segment( $potentialSegment ); + if ( $withConditions ) { - return $segment; - } + $segment['conditions'] = $this->getSegmentConditions( $segment['id'] ); - } + } - return false; + return $segment; + } + } - } + return false; + } - /* - * Compatibility for typo: - * #backward-compatibility - */ - public function getSegementAudience($segmentID=-1,$page=0,$perPage=20,$sortByField='ID',$sortOrder='DESC',$onlyCount=false,$withDND=false){ - return $this->getSegmentAudience( $segmentID, $page, $perPage, $sortByField, $sortOrder, $onlyCount, $withDND ); - } + /* + * Compatibility for typo: + * #backward-compatibility + */ + public function getSegementAudience( $segmentID = -1, $page = 0, $perPage = 20, $sortByField = 'ID', $sortOrder = 'DESC', $onlyCount = false, $withDND = false ) { + return $this->getSegmentAudience( $segmentID, $page, $perPage, $sortByField, $sortOrder, $onlyCount, $withDND ); + } /** * Runs a filtered search on customers based on a segment's condition @@ -749,947 +812,979 @@ public function getSegmentAudience( return false; } - /** - * checks all segments against a contact - */ - public function getSegmentsContainingContact($contactID=-1,$justIDs=false){ - - $ret = array(); - - if ($contactID > 0){ - - // get all segments - $segments = $this->getSegments(-1,1000,0,true); - - if (count($segments) > 0) { - - foreach ($segments as $segment){ - - // pass obj to check (saves it querying) - if ($this->isContactInSegment($contactID, $segment['id'],$segment)){ - - // is in segment - if ($justIDs) - $ret[] = $segment['id']; - else - $ret[] = $segment; - - } - - } // foreach segment - - } // if segments - - } // if contact id - - return $ret; - - } - - /** - * Checks if a contact matches segment conditions - * ... can pass $segmentObj to avoid queries (performance) if already have it - */ - public function isContactInSegment($contactID=-1,$segmentID=-1,$segmentObj=false){ - - if ($segmentID > 0 && $contactID > 0){ - - #} Retrieve segment + conditions - if (is_array($segmentObj)) - $segment = $segmentObj; - else - $segment = $this->getSegment($segmentID,true); - - #} Set these - $conditions = array(); if (isset($segment['conditions'])) $conditions = $segment['conditions']; - $matchType = 'all'; if (isset($segment['matchtype'])) $matchType = $segment['matchtype']; - - try { - - // retrieve getContacts arguments from a list of segment conditions - $contactGetArgs = $this->segmentConditionsToArgs($conditions,$matchType); - - } catch ( Segment_Condition_Exception $exception ){ - - // We're missing the condition class for one or more of this segment's conditions. - $this->segment_error_condition_missing( $segmentID, $exception ); - - // return false, because of the segment error, we cannot be sure. - return false; - - } - - // add paging params - $contactGetArgs['page'] = -1; - $contactGetArgs['perPage'] = -1; - $contactGetArgs['count'] = true; - - // add id check (via rough additionalWhere) - if (!isset($contactGetArgs['additionalWhereArr'])) $contactGetArgs['additionalWhereArr'] = array(); - $contactGetArgs['additionalWhereArr']['idCheck'] = array("ID",'=','%d',$contactID); - - // should only ever be 1 or 0 - $count = $this->DAL()->contacts->getContacts($contactGetArgs); - - if ($count == 1) - return true; - - // nope. - return false; - - } - - return false; - - } - - /** - * Compiles all segments - */ - public function compile_all_segments(){ - - // get all segments - $segments = $this->getSegments(-1,1000,0,true); - - if (count($segments) > 0) foreach ($segments as $segment){ - - // compile this segment - $this->compileSegment( $segment['id'] ); - - } // foreach segment - - return false; - - } - - /** - * Compiles any segments which are affected by a single contact change - * includeSegments is an array of id's - this allows you to pass 'what contact was in before' (because these need --1) - */ - public function compileSegmentsAffectedByContact($contactID=-1,$includeSegments=array()){ - - if ($contactID > 0){ - - // get all segments - $segments = $this->getSegments(-1,1000,0,true); - - if (count($segments) > 0) foreach ($segments as $segment){ - - // pass obj to check (saves it querying) - if ($this->isContactInSegment($contactID, $segment['id'],$segment) || in_array($segment['id'], $includeSegments)){ - - // is in segment - - // compile this segment - $this->compileSegment($segment['id']); - - } - - } // foreach segment - - } // if contact id + /** + * checks all segments against a contact + */ + public function getSegmentsContainingContact( $contactID = -1, $justIDs = false ) { - return false; + $ret = array(); - } + if ( $contactID > 0 ) { - /* - * Compiles any segments which are affected by a quote change - * - * This means segments with conditions of type: - * quotecount - * - * Here we accept a @param of @quote to allow future refinements where by exact conditions are compared. - */ - public function compileSegmentsAffectedByQuote( $quote = array() ){ + // get all segments + $segments = $this->getSegments( -1, 1000, 0, true ); - if ( is_array( $quote ) ){ + if ( count( $segments ) > 0 ) { - // get all segments - $segments = $this->getSegments(-1,1000,0,true); + foreach ( $segments as $segment ) { - if (count($segments) > 0) foreach ($segments as $segment){ + // pass obj to check (saves it querying) + if ( $this->isContactInSegment( $contactID, $segment['id'], $segment ) ) { - // does this segment have a condition we're watching for - if ( $this->segmentHasConditionType( $segment, - array( - 'quotecount' - ) - ) ){ + // is in segment + if ( $justIDs ) { + $ret[] = $segment['id']; + } else { + $ret[] = $segment; + } + } + } // foreach segment - // recompile the segment - $this->compileSegment($segment['id']); + } // if segments - } + } // if contact id - } // foreach segment - - } // if contact id - - return false; - - } - - /* - * Compiles any segments which are affected by an invoice change - * - * This means segments with conditions of type: - * invcount - * successtotaltransval - * - * Here we accept a @param of @invoice to allow future refinements where by exact conditions are compared. - */ - public function compileSegmentsAffectedByInvoice( $invoice = array() ){ - - if ( is_array( $invoice ) ){ - - // get all segments - $segments = $this->getSegments(-1,1000,0,true); - - if (count($segments) > 0) foreach ($segments as $segment){ - - // does this segment have a condition we're watching for - if ( $this->segmentHasConditionType( $segment, - array( - 'invcount', - 'successtotaltransval' - ) - ) ){ - - // recompile the segment - $this->compileSegment($segment['id']); - - } - - } // foreach segment - - } // if contact id - - return false; - - } - - /* - * Compiles any segments which are affected by a transaction change - * - * This means segments with conditions of type: - * trancount - * successsingletransval - * successtotaltransval - * successtransref - * successtransname - * successtransstr - * - * Here we accept a @param of @transaction to allow future refinements where by exact conditions are compared. - * - */ - public function compileSegmentsAffectedByTransaction( $transaction = array() ){ - - if ( is_array( $transaction ) ){ - - // get all segments - $segments = $this->getSegments(-1,1000,0,true); - - if (count($segments) > 0) foreach ($segments as $segment){ - - // does this segment have a condition we're watching for - if ( $this->segmentHasConditionType( $segment, - array( - 'trancount', - 'successsingletransval', - 'successtotaltransval', - 'successtransref', - 'successtransname', - 'successtransstr' - ) - ) ){ - - // recompile the segment - $this->compileSegment($segment['id']); - - } + return $ret; + } - } // foreach segment + /** + * Checks if a contact matches segment conditions + * ... can pass $segmentObj to avoid queries (performance) if already have it + */ + public function isContactInSegment( $contactID = -1, $segmentID = -1, $segmentObj = false ) { - } // if contact id + if ( $segmentID > 0 && $contactID > 0 ) { - return false; + #} Retrieve segment + conditions + if ( is_array( $segmentObj ) ) { + $segment = $segmentObj; + } else { + $segment = $this->getSegment( $segmentID, true ); + } - } + #} Set these + $conditions = array(); + if ( isset( $segment['conditions'] ) ) { + $conditions = $segment['conditions']; + } + $matchType = 'all'; + if ( isset( $segment['matchtype'] ) ) { + $matchType = $segment['matchtype']; + } + try { - - /** - * - */ - public function getSegmentConditions($segmentID=-1){ + // retrieve getContacts arguments from a list of segment conditions + $contactGetArgs = $this->segmentConditionsToArgs( $conditions, $matchType ); - if ($segmentID > 0){ + } catch ( Segment_Condition_Exception $exception ) { - global $ZBSCRM_t,$wpdb; + // We're missing the condition class for one or more of this segment's conditions. + $this->segment_error_condition_missing( $segmentID, $exception ); - $potentialSegmentConditions = $wpdb->get_results( $this->prepare("SELECT * FROM ".$ZBSCRM_t['segmentsconditions']." WHERE zbscondition_segmentid = %d",$segmentID) ); + // return false, because of the segment error, we cannot be sure. + return false; - if (is_array($potentialSegmentConditions) && count($potentialSegmentConditions) > 0) { + } - $returnConditions = array(); + // add paging params + $contactGetArgs['page'] = -1; + $contactGetArgs['perPage'] = -1; + $contactGetArgs['count'] = true; - foreach ($potentialSegmentConditions as $condition){ + // add id check (via rough additionalWhere) + if ( ! isset( $contactGetArgs['additionalWhereArr'] ) ) { + $contactGetArgs['additionalWhereArr'] = array(); + } + $contactGetArgs['additionalWhereArr']['idCheck'] = array( 'ID', '=', '%d', $contactID ); - $returnConditions[] = $this->tidy_segment_condition($condition); + // should only ever be 1 or 0 + $count = $this->DAL()->contacts->getContacts( $contactGetArgs ); - } + if ( $count == 1 ) { + return true; + } + // nope. + return false; - return $returnConditions; + } - } - + return false; + } - } + /** + * Compiles all segments + */ + public function compile_all_segments() { - return false; - - } + // get all segments + $segments = $this->getSegments( -1, 1000, 0, true ); + if ( count( $segments ) > 0 ) { + foreach ( $segments as $segment ) { - /** - * Simple func to update the segment compiled count (says how many contacts currently in segment) - */ - public function updateSegmentCompiled($segmentID=-1,$segmentCount=0,$compiledUTS=-1){ - - global $ZBSCRM_t,$wpdb; + // compile this segment + $this->compileSegment( $segment['id'] ); - if ($segmentID > 0){ + } // foreach segment + } - // checks - $count = 0; if ($segmentCount > 0) $count = (int)$segmentCount; - $compiled = time(); if ($compiledUTS > 0) $compiled = (int)$compiledUTS; + return false; + } - if ($wpdb->update( - $ZBSCRM_t['segments'], - array( - 'zbsseg_compilecount' => $count, - 'zbsseg_lastcompiled' => $compiled - ), - array( // where - 'ID' => $segmentID - ), - array( - '%d', - '%d' - ), - array( - '%d' - ) - ) !== false){ + /** + * Compiles any segments which are affected by a single contact change + * includeSegments is an array of id's - this allows you to pass 'what contact was in before' (because these need --1) + */ + public function compileSegmentsAffectedByContact( $contactID = -1, $includeSegments = array() ) { - // udpdated - return true; + if ( $contactID > 0 ) { - } else { + // get all segments + $segments = $this->getSegments( -1, 1000, 0, true ); - // could not update?! - return false; + if ( count( $segments ) > 0 ) { + foreach ( $segments as $segment ) { - } + // pass obj to check (saves it querying) + if ( $this->isContactInSegment( $contactID, $segment['id'], $segment ) || in_array( $segment['id'], $includeSegments ) ) { + // is in segment - } + // compile this segment + $this->compileSegment( $segment['id'] ); - } + } + } // foreach segment + } + } // if contact id - /** - * - */ - public function addUpdateSegment($segmentID=-1,$segmentOwner=-1,$segmentName='',$segmentConditions=array(),$segmentMatchType='all',$forceCompile=false){ + return false; + } - global $ZBSCRM_t,$wpdb; + /* + * Compiles any segments which are affected by a quote change + * + * This means segments with conditions of type: + * quotecount + * + * Here we accept a @param of @quote to allow future refinements where by exact conditions are compared. + */ + public function compileSegmentsAffectedByQuote( $quote = array() ) { + + if ( is_array( $quote ) ) { + + // get all segments + $segments = $this->getSegments( -1, 1000, 0, true ); + + if ( count( $segments ) > 0 ) { + foreach ( $segments as $segment ) { + + // does this segment have a condition we're watching for + if ( $this->segmentHasConditionType( + $segment, + array( + 'quotecount', + ) + ) ) { + + // recompile the segment + $this->compileSegment( $segment['id'] ); + + } + } // foreach segment + } + } // if contact id - #} After ops, shall I compile audience? - $toCompile = $forceCompile; + return false; + } - if ($segmentID > 0){ + /* + * Compiles any segments which are affected by an invoice change + * + * This means segments with conditions of type: + * invcount + * successtotaltransval + * + * Here we accept a @param of @invoice to allow future refinements where by exact conditions are compared. + */ + public function compileSegmentsAffectedByInvoice( $invoice = array() ) { + + if ( is_array( $invoice ) ) { + + // get all segments + $segments = $this->getSegments( -1, 1000, 0, true ); + + if ( count( $segments ) > 0 ) { + foreach ( $segments as $segment ) { + + // does this segment have a condition we're watching for + if ( $this->segmentHasConditionType( + $segment, + array( + 'invcount', + 'successtotaltransval', + ) + ) ) { + + // recompile the segment + $this->compileSegment( $segment['id'] ); + + } + } // foreach segment + } + } // if contact id - #} Update a segment + return false; + } - #} Owner - if -1 then use current user - if ($segmentOwner <= 0) $segmentOwner = get_current_user_id(); + /* + * Compiles any segments which are affected by a transaction change + * + * This means segments with conditions of type: + * trancount + * successsingletransval + * successtotaltransval + * successtransref + * successtransname + * successtransstr + * + * Here we accept a @param of @transaction to allow future refinements where by exact conditions are compared. + * + */ + public function compileSegmentsAffectedByTransaction( $transaction = array() ) { + + if ( is_array( $transaction ) ) { + + // get all segments + $segments = $this->getSegments( -1, 1000, 0, true ); + + if ( count( $segments ) > 0 ) { + foreach ( $segments as $segment ) { + + // does this segment have a condition we're watching for + if ( $this->segmentHasConditionType( + $segment, + array( + 'trancount', + 'successsingletransval', + 'successtotaltransval', + 'successtransref', + 'successtransname', + 'successtransstr', + ) + ) ) { + + // recompile the segment + $this->compileSegment( $segment['id'] ); + + } + } // foreach segment + } + } // if contact id - #} Empty name = untitled - if (empty($segmentName)) $segmentName = __('Untitled Segment',"zero-bs-crm"); + return false; + } - // slug auto-updates with name, (fix later if issue) - // in fact, just leave as whatever first set? (affects quickfilter URLs etc?) - // just did in end - #} Generate slug - $segmentSlug = $this->makeSlug($segmentName); + /** + * + */ + public function getSegmentConditions( $segmentID = -1 ) { - #} update header line - if ($wpdb->update( - $ZBSCRM_t['segments'], - array( - 'zbs_owner' => $segmentOwner, - 'zbsseg_name' => $segmentName, - 'zbsseg_slug' => $segmentSlug, - 'zbsseg_matchtype' => $segmentMatchType, - 'zbsseg_lastupdated' => time() - ), - array( // where - 'ID' => $segmentID - ), - array( - '%d', - '%s', - '%s', - '%s', - '%d' - ), - array( - '%d' - ) - ) !== false){ + if ( $segmentID > 0 ) { - // updated, move on.. + global $ZBSCRM_t, $wpdb; - // add segment conditions - $this->addUpdateSegmentConditions($segmentID,$segmentConditions); + $potentialSegmentConditions = $wpdb->get_results( $this->prepare( 'SELECT * FROM ' . $ZBSCRM_t['segmentsconditions'] . ' WHERE zbscondition_segmentid = %d', $segmentID ) ); - // return id - $returnID = $segmentID; + if ( is_array( $potentialSegmentConditions ) && count( $potentialSegmentConditions ) > 0 ) { - // force to compile - $toCompile = true; $compileID = $segmentID; + $returnConditions = array(); - } else { + foreach ( $potentialSegmentConditions as $condition ) { - // could not update?! - return false; + $returnConditions[] = $this->tidy_segment_condition( $condition ); - } - + } - } else { + return $returnConditions; - #} Add a new segment + } + } - #} Owner - if -1 then use current user - if ($segmentOwner <= 0) $segmentOwner = get_current_user_id(); + return false; + } - #} Empty name = untitled (should never happen because of UI) - if (empty($segmentName)) $segmentName = __('Untitled Segment',"zero-bs-crm"); + /** + * Simple func to update the segment compiled count (says how many contacts currently in segment) + */ + public function updateSegmentCompiled( $segmentID = -1, $segmentCount = 0, $compiledUTS = -1 ) { - #} Generate slug - $segmentSlug = $this->makeSlug($segmentName); + global $ZBSCRM_t, $wpdb; - #} Add header line - if ($wpdb->insert( - $ZBSCRM_t['segments'], - array( - 'zbs_owner' => $segmentOwner, - 'zbsseg_name' => $segmentName, - 'zbsseg_slug' => $segmentSlug, - 'zbsseg_matchtype' => $segmentMatchType, - 'zbsseg_created' => time(), - 'zbsseg_lastupdated' => time(), - 'zbsseg_lastcompiled' => time(), // we'll compile it shortly, set as now :) - ), - array( - '%d', - '%s', - '%s', - '%s', - '%d', - '%d', - '%d' - ) - ) > 0){ + if ( $segmentID > 0 ) { - // inserted, let's move on - $newSegmentID = $wpdb->insert_id; + // checks + $count = 0; + if ( $segmentCount > 0 ) { + $count = (int) $segmentCount; + } + $compiled = time(); + if ( $compiledUTS > 0 ) { + $compiled = (int) $compiledUTS; + } - // add segment conditions - $this->addUpdateSegmentConditions($newSegmentID,$segmentConditions); + if ( $wpdb->update( + $ZBSCRM_t['segments'], + array( + 'zbsseg_compilecount' => $count, + 'zbsseg_lastcompiled' => $compiled, + ), + array( // where + 'ID' => $segmentID, + ), + array( + '%d', + '%d', + ), + array( + '%d', + ) + ) !== false ) { + + // udpdated + return true; - // force to compile - $toCompile = true; $compileID = $newSegmentID; + } else { - // return id - $returnID = $newSegmentID; + // could not update?! + return false; - } else { + } + } + } - // could not insert?! - return false; + /** + * + */ + public function addUpdateSegment( $segmentID = -1, $segmentOwner = -1, $segmentName = '', $segmentConditions = array(), $segmentMatchType = 'all', $forceCompile = false ) { - } + global $ZBSCRM_t, $wpdb; - } // / new + #} After ops, shall I compile audience? + $toCompile = $forceCompile; - // "compile" segments? - if ($toCompile && !empty($compileID)){ + if ( $segmentID > 0 ) { - // compiles + logs how many in segment against record - $totalInSegment = $this->compileSegment($compileID); + #} Update a segment - } + #} Owner - if -1 then use current user + if ( $segmentOwner <= 0 ) { + $segmentOwner = get_current_user_id(); + } - if (isset($returnID)) - return $returnID; - else - return false; - - } + #} Empty name = untitled + if ( empty( $segmentName ) ) { + $segmentName = __( 'Untitled Segment', 'zero-bs-crm' ); + } + // slug auto-updates with name, (fix later if issue) + // in fact, just leave as whatever first set? (affects quickfilter URLs etc?) + // just did in end + #} Generate slug + $segmentSlug = $this->makeSlug( $segmentName ); + + #} update header line + if ( $wpdb->update( + $ZBSCRM_t['segments'], + array( + 'zbs_owner' => $segmentOwner, + 'zbsseg_name' => $segmentName, + 'zbsseg_slug' => $segmentSlug, + 'zbsseg_matchtype' => $segmentMatchType, + 'zbsseg_lastupdated' => time(), + ), + array( // where + 'ID' => $segmentID, + ), + array( + '%d', + '%s', + '%s', + '%s', + '%d', + ), + array( + '%d', + ) + ) !== false ) { + + // updated, move on.. + + // add segment conditions + $this->addUpdateSegmentConditions( $segmentID, $segmentConditions ); + + // return id + $returnID = $segmentID; + + // force to compile + $toCompile = true; + $compileID = $segmentID; - public function addUpdateSegmentConditions($segmentID=-1,$conditions=array()){ + } else { - if ($segmentID > 0 && is_array($conditions)){ + // could not update?! + return false; - // lazy - here I NUKE all existing conditions then readd... - $this->removeSegmentConditions($segmentID); + } + } else { - if (is_array($conditions) && count($conditions) > 0){ + #} Add a new segment - $retConditions = array(); + #} Owner - if -1 then use current user + if ( $segmentOwner <= 0 ) { + $segmentOwner = get_current_user_id(); + } - foreach ($conditions as $sCondition){ + #} Empty name = untitled (should never happen because of UI) + if ( empty( $segmentName ) ) { + $segmentName = __( 'Untitled Segment', 'zero-bs-crm' ); + } + #} Generate slug + $segmentSlug = $this->makeSlug( $segmentName ); + + #} Add header line + if ( $wpdb->insert( + $ZBSCRM_t['segments'], + array( + 'zbs_owner' => $segmentOwner, + 'zbsseg_name' => $segmentName, + 'zbsseg_slug' => $segmentSlug, + 'zbsseg_matchtype' => $segmentMatchType, + 'zbsseg_created' => time(), + 'zbsseg_lastupdated' => time(), + 'zbsseg_lastcompiled' => time(), // we'll compile it shortly, set as now :) + ), + array( + '%d', + '%s', + '%s', + '%s', + '%d', + '%d', + '%d', + ) + ) > 0 ) { + + // inserted, let's move on + $newSegmentID = $wpdb->insert_id; + + // add segment conditions + $this->addUpdateSegmentConditions( $newSegmentID, $segmentConditions ); + + // force to compile + $toCompile = true; + $compileID = $newSegmentID; + + // return id + $returnID = $newSegmentID; - $newConditionID = $this->addUpdateSegmentCondition(-1,$segmentID,$sCondition); + } else { - if (!empty($newConditionID)){ + // could not insert?! + return false; - // new condition added, insert - $retConditions[$newConditionID] = $sCondition; + } + } // / new - } else { + // "compile" segments? + if ( $toCompile && ! empty( $compileID ) ) { - // error inserting condition?! - return false; + // compiles + logs how many in segment against record + $totalInSegment = $this->compileSegment( $compileID ); - } + } - } + if ( isset( $returnID ) ) { + return $returnID; + } else { + return false; + } + } - return $retConditions; + public function addUpdateSegmentConditions( $segmentID = -1, $conditions = array() ) { - } + if ( $segmentID > 0 && is_array( $conditions ) ) { + // lazy - here I NUKE all existing conditions then readd... + $this->removeSegmentConditions( $segmentID ); - } + if ( is_array( $conditions ) && count( $conditions ) > 0 ) { - return array(); + $retConditions = array(); - } + foreach ( $conditions as $sCondition ) { - /** - * - */ - public function addUpdateSegmentCondition($conditionID=-1,$segmentID=-1,$conditionDetails=array()){ + $newConditionID = $this->addUpdateSegmentCondition( -1, $segmentID, $sCondition ); - global $ZBSCRM_t,$wpdb; + if ( ! empty( $newConditionID ) ) { - #} Check/build empty condition details - $condition = array( - 'type' => '', - 'operator' => '', - 'val' => '', - 'valsecondary' => '' - ); - if (isset($conditionDetails['type'])) $condition['type'] = $conditionDetails['type']; - if (isset($conditionDetails['value'])) $condition['val'] = $conditionDetails['value']; - if (isset($conditionDetails['operator']) && $conditionDetails['operator'] !== -1) $condition['operator'] = $conditionDetails['operator']; - if (isset($conditionDetails['value2'])) $condition['valsecondary'] = $conditionDetails['value2']; + // new condition added, insert + $retConditions[ $newConditionID ] = $sCondition; - // update or insert? - if ($conditionID > 0){ + } else { - #} Update a segment condition + // error inserting condition?! + return false; - #} update line - if ($wpdb->update( - $ZBSCRM_t['segmentsconditions'], - array( - 'zbscondition_segmentid' => $segmentID, - 'zbscondition_type' => $condition['type'], - 'zbscondition_op' => $condition['operator'], - 'zbscondition_val' => $condition['val'], - 'zbscondition_val_secondary' => $condition['valsecondary'] - ), - array( // where - 'ID' => $conditionID - ), - array( - '%d', - '%s', - '%s', - '%s', - '%s' - ), - array( - '%d' - ) - ) !== false){ + } + } - return $conditionID; + return $retConditions; - } else { + } + } - // could not update?! - return false; + return array(); + } - } - + /** + * + */ + public function addUpdateSegmentCondition( $conditionID = -1, $segmentID = -1, $conditionDetails = array() ) { + + global $ZBSCRM_t, $wpdb; + + #} Check/build empty condition details + $condition = array( + 'type' => '', + 'operator' => '', + 'val' => '', + 'valsecondary' => '', + ); + if ( isset( $conditionDetails['type'] ) ) { + $condition['type'] = $conditionDetails['type']; + } + if ( isset( $conditionDetails['value'] ) ) { + $condition['val'] = $conditionDetails['value']; + } + if ( isset( $conditionDetails['operator'] ) && $conditionDetails['operator'] !== -1 ) { + $condition['operator'] = $conditionDetails['operator']; + } + if ( isset( $conditionDetails['value2'] ) ) { + $condition['valsecondary'] = $conditionDetails['value2']; + } - } else { + // update or insert? + if ( $conditionID > 0 ) { + + #} Update a segment condition + + #} update line + if ( $wpdb->update( + $ZBSCRM_t['segmentsconditions'], + array( + 'zbscondition_segmentid' => $segmentID, + 'zbscondition_type' => $condition['type'], + 'zbscondition_op' => $condition['operator'], + 'zbscondition_val' => $condition['val'], + 'zbscondition_val_secondary' => $condition['valsecondary'], + ), + array( // where + 'ID' => $conditionID, + ), + array( + '%d', + '%s', + '%s', + '%s', + '%s', + ), + array( + '%d', + ) + ) !== false ) { + + return $conditionID; - #} Add a new segmentcondition + } else { + // could not update?! + return false; - #} Add condition line - if ($wpdb->insert( - $ZBSCRM_t['segmentsconditions'], - array( - 'zbscondition_segmentid' => $segmentID, - 'zbscondition_type' => $condition['type'], - 'zbscondition_op' => $condition['operator'], - 'zbscondition_val' => $condition['val'], - 'zbscondition_val_secondary' => $condition['valsecondary'] - ), - array( - '%d', - '%s', - '%s', - '%s', - '%s' - ) - ) > 0){ + } + } else { + + #} Add a new segmentcondition + + #} Add condition line + if ( $wpdb->insert( + $ZBSCRM_t['segmentsconditions'], + array( + 'zbscondition_segmentid' => $segmentID, + 'zbscondition_type' => $condition['type'], + 'zbscondition_op' => $condition['operator'], + 'zbscondition_val' => $condition['val'], + 'zbscondition_val_secondary' => $condition['valsecondary'], + ), + array( + '%d', + '%s', + '%s', + '%s', + '%s', + ) + ) > 0 ) { + + // inserted + return $wpdb->insert_id; + } else { - // inserted - return $wpdb->insert_id; + // could not insert?! + return false; - } else { + } + } // / new - // could not insert?! - return false; + return false; + } - } + /** + * Does the segment have a condition of type x? + * + * @param array segment - segment obj as returned by getSegment(s) + * @param array condition_type - array of condition types to check for + */ + public function segmentHasConditionType( $segment = array(), $condition_types = array() ) { - } // / new + // got a legit segment, and some conditions? + if ( is_array( $segment ) && isset( $segment['conditions'] ) && is_array( $segment['conditions'] ) && is_array( $condition_types ) ) { - return false; + // cycle through segment conditions & check + foreach ( $segment['conditions'] as $condition ) { - - } + if ( in_array( $condition['type'], $condition_types ) ) { + return true; + } + } + } + return false; + } - /** - * Does the segment have a condition of type x? - * - * @param array segment - segment obj as returned by getSegment(s) - * @param array condition_type - array of condition types to check for - */ - public function segmentHasConditionType( $segment = array(), $condition_types = array() ){ + /** + * empty all conditions against seg + */ + public function removeSegmentConditions( $segmentID = -1 ) { - // got a legit segment, and some conditions? - if ( is_array( $segment ) && isset( $segment['conditions'] ) && is_array( $segment['conditions'] ) && is_array( $condition_types ) ){ + if ( ! empty( $segmentID ) ) { - // cycle through segment conditions & check - foreach ( $segment['conditions'] as $condition ){ + global $ZBSCRM_t, $wpdb; - if ( in_array( $condition['type'], $condition_types ) ) return true; + return $wpdb->delete( + $ZBSCRM_t['segmentsconditions'], + array( // where + 'zbscondition_segmentid' => $segmentID, + ), + array( + '%d', + ) + ); - } + } + return false; + } - } + /** + * Segment rules + * takes a condition + returns a contact dal2 get arr param + */ + public function segmentConditionArgs( $condition = array(), $conditionKeySuffix = '' ) { - return false; - - } + if ( is_array( $condition ) && isset( $condition['type'] ) && isset( $condition['operator'] ) ) { - /** - * empty all conditions against seg - */ - public function removeSegmentConditions($segmentID=-1){ + global $zbs, $wpdb, $ZBSCRM_t; - if (!empty($segmentID)) { + if ( ! empty( $condition['type'] ) ) { + // normalise type string + $condition_type = preg_replace( '/^zbsc_/', '', $condition['type'] ); + $filter_tag = $this->makeSlug( $condition_type ) . '_zbsSegmentArgumentBuild'; - global $ZBSCRM_t,$wpdb; + $potential_args = apply_filters( $filter_tag, false, $condition, $conditionKeySuffix ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // got anything back? - return $wpdb->delete( - $ZBSCRM_t['segmentsconditions'], - array( // where - 'zbscondition_segmentid' => $segmentID - ), - array( - '%d' - ) - ); + if ( $potential_args !== false ) { + return $potential_args; + } + } - } + switch ( $condition['type'] ) { - return false; - - } + case 'status': + case 'zbsc_status': + /* + while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: + if ($condition['operator'] == 'equal') + return array('hasStatus'=>$condition['value']); + else + return array('otherStatus'=>$condition['value']); + */ + if ( $condition['operator'] == 'equal' ) { + return array( + 'additionalWhereArr' => + array( 'statusEqual' . $conditionKeySuffix => array( 'zbsc_status', '=', '%s', $condition['value'] ) ), + ); + } else { + return array( + 'additionalWhereArr' => + array( 'statusEqual' . $conditionKeySuffix => array( 'zbsc_status', '<>', '%s', $condition['value'] ) ), + ); + } + break; + case 'fullname': // 'equal','notequal','contains' + if ( $condition['operator'] == 'equal' ) { + return array( + 'additionalWhereArr' => + array( 'fullnameEqual' . $conditionKeySuffix => array( "CONCAT(zbsc_fname,' ',zbsc_lname)", '=', '%s', $condition['value'] ) ), + ); + } elseif ( $condition['operator'] == 'notequal' ) { + return array( + 'additionalWhereArr' => + array( 'fullnameEqual' . $conditionKeySuffix => array( "CONCAT(zbsc_fname,' ',zbsc_lname)", '<>', '%s', $condition['value'] ) ), + ); + } elseif ( $condition['operator'] == 'contains' ) { + return array( + 'additionalWhereArr' => + array( 'fullnameEqual' . $conditionKeySuffix => array( "CONCAT(zbsc_fname,' ',zbsc_lname)", 'LIKE', '%s', '%' . $condition['value'] . '%' ) ), + ); + } + break; - /** - * Segment rules - * takes a condition + returns a contact dal2 get arr param - * - */ - public function segmentConditionArgs($condition=array(),$conditionKeySuffix=''){ + case 'email': + case 'zbsc_email': + if ( $condition['operator'] == 'equal' ) { + // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: + // return array('hasEmail'=>$condition['value']); + /* + // this was good, but was effectively AND + return array('additionalWhereArr'=> + array( + 'email'.$conditionKeySuffix=>array('zbsc_email','=','%s',$condition['value']), + 'emailAKA'.$conditionKeySuffix=>array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$condition['value']) + ) + ); + */ + // This was required to work with OR (e.g. postcode 1 = x or postcode 2 = x) + // ----------------------- + // This generates a query like 'zbsc_fname LIKE %s OR zbsc_lname LIKE %s', + // which we then need to include as direct subquery + /* + THIS WORKS: but refactored below + $conditionQArr = $this->buildWheres(array( + 'email'.$conditionKeySuffix=>array('zbsc_email','=','%s',$condition['value']), + 'emailAKA'.$conditionKeySuffix=>array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$condition['value']) + ),'',array(),'OR',false); + if (is_array($conditionQArr) && isset($conditionQArr['where']) && !empty($conditionQArr['where'])){ + return array('additionalWhereArr'=>array('direct'=>array(array('('.$conditionQArr['where'].')',$conditionQArr['params'])))); + } + return array(); + */ + // this way for OR situations + return $this->segmentBuildDirectOrClause( + array( + 'email' . $conditionKeySuffix => array( 'zbsc_email', '=', '%s', $condition['value'] ), + 'emailAKA' . $conditionKeySuffix => array( 'ID', 'IN', '(SELECT aka_id FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_alias = %s)', $condition['value'] ), + ), + 'OR' + ); + // ----------------------- + } elseif ( $condition['operator'] == 'notequal' ) { + return array( + 'additionalWhereArr' => + array( + 'notEmail' . $conditionKeySuffix => array( 'zbsc_email', '<>', '%s', $condition['value'] ), + 'notEmailAka' . $conditionKeySuffix => array( 'ID', 'NOT IN', '(SELECT aka_id FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_alias = %s)', $condition['value'] ), + ), + ); + } elseif ( $condition['operator'] == 'contains' ) { + return array( + 'additionalWhereArr' => + array( 'emailContains' . $conditionKeySuffix => array( 'zbsc_email', 'LIKE', '%s', '%' . $condition['value'] . '%' ) ), + ); + } - if (is_array($condition) && isset($condition['type']) && isset($condition['operator'])){ + break; - global $zbs,$wpdb,$ZBSCRM_t; + // TBA (When DAL2 trans etc.) + case 'totalval': // 'equal','notequal','larger','less','floatrange' + break; - if ( ! empty( $condition['type'] ) ) { - // normalise type string - $condition_type = preg_replace( '/^zbsc_/', '', $condition['type'] ); - $filter_tag = $this->makeSlug( $condition_type ) . '_zbsSegmentArgumentBuild'; + case 'dateadded': // 'before','after','daterange','datetimerange','beforeequal','afterequal','previousdays' + // date added + if ( $condition['operator'] == 'before' ) { + return array( + 'additionalWhereArr' => + array( 'olderThan' . $conditionKeySuffix => array( 'zbsc_created', '<', '%d', $condition['value'] ) ), + ); + } elseif ( $condition['operator'] == 'beforeequal' ) { + return array( + 'additionalWhereArr' => + array( 'olderThanEqual' . $conditionKeySuffix => array( 'zbsc_created', '<=', '%d', $condition['value'] ) ), + ); + } elseif ( $condition['operator'] == 'after' ) { + return array( + 'additionalWhereArr' => + array( 'newerThan' . $conditionKeySuffix => array( 'zbsc_created', '>', '%d', $condition['value'] ) ), + ); + } elseif ( $condition['operator'] == 'afterequal' ) { + return array( + 'additionalWhereArr' => + array( 'newerThanEqual' . $conditionKeySuffix => array( 'zbsc_created', '>=', '%d', $condition['value'] ) ), + ); + } elseif ( + $condition['operator'] == 'daterange' + || + $condition['operator'] == 'datetimerange' + ) { + + $before = false; + $after = false; + // split out the value + if ( isset( $condition['value'] ) && ! empty( $condition['value'] ) ) { + $after = (int) $condition['value']; + } + if ( isset( $condition['value2'] ) && ! empty( $condition['value2'] ) ) { + $before = (int) $condition['value2']; + } + + // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: + // return array('newerThan'=>$after,'olderThan'=>$before); + return array( + 'additionalWhereArr' => + array( + 'newerThan' . $conditionKeySuffix => array( 'zbsc_created', '>=', '%d', $condition['value'] ), + 'olderThan' . $conditionKeySuffix => array( 'zbsc_created', '<=', '%d', $condition['value2'] ), + ), + ); + } elseif ( $condition['operator'] == 'previousdays' ) { + + $days_value = (int) $condition['value']; + $midnight = strtotime( 'midnight' ); + $previous_days_uts = $midnight - ( ( 60 * 60 * 24 ) * $days_value ); + + return array( + 'additionalWhereArr' => + array( + 'newerThanPreviousDays' . $conditionKeySuffix => array( 'zbsc_created', '<=', '%d', time() ), + 'olderThanPreviousDays' . $conditionKeySuffix => array( 'zbsc_created', '>=', '%d', $previous_days_uts ), + ), + ); + } - $potential_args = apply_filters( $filter_tag, false, $condition, $conditionKeySuffix ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // got anything back? + break; - if ( $potential_args !== false ) { - return $potential_args; - } - } + case 'datelastcontacted': // 'before','after','daterange','datetimerange','beforeequal','afterequal','previousdays' + // contactedAfter + if ( $condition['operator'] == 'before' ) { // datetime + return array( + 'additionalWhereArr' => + array( 'contactedBefore' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '<', '%d', $condition['value'] ) ), + ); + } elseif ( $condition['operator'] == 'beforeequal' ) { // date + return array( + 'additionalWhereArr' => + array( 'contactedBeforeEqual' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '<=', '%d', $condition['value'] ) ), + ); + } elseif ( $condition['operator'] == 'after' ) { // datetime + return array( + 'additionalWhereArr' => + array( 'contactedAfter' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '>', '%d', $condition['value'] ) ), + ); + } elseif ( $condition['operator'] == 'afterequal' ) { // date + return array( + 'additionalWhereArr' => + array( 'contactedAfterEqual' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '>=', '%d', $condition['value'] ) ), + ); + } elseif ( + $condition['operator'] == 'daterange' + || + $condition['operator'] == 'datetimerange' + ) { + + $before = false; + $after = false; + // split out the value + if ( isset( $condition['value'] ) && ! empty( $condition['value'] ) ) { + $after = (int) $condition['value']; + } + if ( isset( $condition['value2'] ) && ! empty( $condition['value2'] ) ) { + $before = (int) $condition['value2']; + } + + // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: + // return array('contactedAfter'=>$after,'contactedBefore'=>$before); + return array( + 'additionalWhereArr' => + array( + 'contactedAfter' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '>=', '%d', $after ), + 'contactedBefore' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '<=', '%d', $before ), + ), + ); + } elseif ( $condition['operator'] == 'previousdays' ) { + + $days_value = (int) $condition['value']; + $previous_days_uts = strtotime( '-' . $days_value . ' days' ); + + return array( + 'additionalWhereArr' => + array( + 'contactedAfterPreviousDays' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '<=', '%d', time() ), + 'contactedBeforePreviousDays' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '>=', '%d', $previous_days_uts ), + ), + ); + } - switch ( $condition['type'] ) { + break; - case 'status': - case 'zbsc_status': - - /* while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: - if ($condition['operator'] == 'equal') - return array('hasStatus'=>$condition['value']); - else - return array('otherStatus'=>$condition['value']); - */ - if ($condition['operator'] == 'equal') - return array('additionalWhereArr'=> - array('statusEqual'.$conditionKeySuffix=>array("zbsc_status",'=','%s',$condition['value'])) - ); - else - return array('additionalWhereArr'=> - array('statusEqual'.$conditionKeySuffix=>array("zbsc_status",'<>','%s',$condition['value'])) - ); - - break; - - case 'fullname': // 'equal','notequal','contains' - - if ($condition['operator'] == 'equal') - return array('additionalWhereArr'=> - array('fullnameEqual'.$conditionKeySuffix=>array("CONCAT(zbsc_fname,' ',zbsc_lname)",'=','%s',$condition['value'])) - ); - elseif ($condition['operator'] == 'notequal') - return array('additionalWhereArr'=> - array('fullnameEqual'.$conditionKeySuffix=>array("CONCAT(zbsc_fname,' ',zbsc_lname)",'<>','%s',$condition['value'])) - ); - elseif ($condition['operator'] == 'contains') - return array('additionalWhereArr'=> - array('fullnameEqual'.$conditionKeySuffix=>array("CONCAT(zbsc_fname,' ',zbsc_lname)",'LIKE','%s','%'.$condition['value'].'%')) - ); - break; - - case 'email': - case 'zbsc_email': - - if ($condition['operator'] == 'equal'){ - // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: - // return array('hasEmail'=>$condition['value']); - /* // this was good, but was effectively AND - return array('additionalWhereArr'=> - array( - 'email'.$conditionKeySuffix=>array('zbsc_email','=','%s',$condition['value']), - 'emailAKA'.$conditionKeySuffix=>array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$condition['value']) - ) - ); - */ - // This was required to work with OR (e.g. postcode 1 = x or postcode 2 = x) - // ----------------------- - // This generates a query like 'zbsc_fname LIKE %s OR zbsc_lname LIKE %s', - // which we then need to include as direct subquery - /* THIS WORKS: but refactored below - $conditionQArr = $this->buildWheres(array( - 'email'.$conditionKeySuffix=>array('zbsc_email','=','%s',$condition['value']), - 'emailAKA'.$conditionKeySuffix=>array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$condition['value']) - ),'',array(),'OR',false); - if (is_array($conditionQArr) && isset($conditionQArr['where']) && !empty($conditionQArr['where'])){ - return array('additionalWhereArr'=>array('direct'=>array(array('('.$conditionQArr['where'].')',$conditionQArr['params'])))); - } - return array(); - */ - // this way for OR situations - return $this->segmentBuildDirectOrClause(array( - 'email'.$conditionKeySuffix=>array('zbsc_email','=','%s',$condition['value']), - 'emailAKA'.$conditionKeySuffix=>array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$condition['value']) - ),'OR'); - // ----------------------- - } elseif ($condition['operator'] == 'notequal') - return array('additionalWhereArr'=> - array( - 'notEmail'.$conditionKeySuffix=>array('zbsc_email','<>','%s',$condition['value']), - 'notEmailAka'.$conditionKeySuffix=>array('ID','NOT IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$condition['value']) - ) - ); - elseif ($condition['operator'] == 'contains') - return array('additionalWhereArr'=> - array('emailContains'.$conditionKeySuffix=>array("zbsc_email",'LIKE','%s','%'.$condition['value'].'%')) - ); + case 'tagged': // 'tag' + // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: + // return array('isTagged'=>$condition['value']); + // NOTE + // ... this is a DIRECT query, so format for adding here is a little diff + // ... and only works (not overriding existing ['direct']) because the calling func of this func has to especially copy separately + return array( + 'additionalWhereArr' => + array( + 'direct' => array( + array( '(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = contact.ID AND zbstl_tagid = %d) > 0', array( ZBS_TYPE_CONTACT, $condition['value'] ) ), + ), + ), + ); break; - // TBA (When DAL2 trans etc.) - case 'totalval': // 'equal','notequal','larger','less','floatrange' - - break; - - case 'dateadded': // 'before','after','daterange','datetimerange','beforeequal','afterequal','previousdays' - - // date added - if ($condition['operator'] == 'before') - return array('additionalWhereArr'=> - array('olderThan'.$conditionKeySuffix=>array('zbsc_created','<','%d',$condition['value'])) - ); - elseif ($condition['operator'] == 'beforeequal') - return array('additionalWhereArr'=> - array( 'olderThanEqual' . $conditionKeySuffix => array( 'zbsc_created', '<=', '%d', $condition['value'] ) ) - ); - elseif ($condition['operator'] == 'after') - return array('additionalWhereArr'=> - array('newerThan'.$conditionKeySuffix=>array('zbsc_created','>','%d',$condition['value'])) - ); - elseif ($condition['operator'] == 'afterequal') - return array('additionalWhereArr'=> - array( 'newerThanEqual' . $conditionKeySuffix => array( 'zbsc_created', '>=', '%d', $condition['value'] ) ) - ); - elseif ( - $condition['operator'] == 'daterange' - || - $condition['operator'] == 'datetimerange' - ){ - - $before = false; $after = false; - // split out the value - if (isset($condition['value']) && !empty($condition['value'])) $after = (int)$condition['value']; - if (isset($condition['value2']) && !empty($condition['value2'])) $before = (int)$condition['value2']; - - // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: - // return array('newerThan'=>$after,'olderThan'=>$before); - return array('additionalWhereArr'=> - array( - 'newerThan' . $conditionKeySuffix => array( 'zbsc_created', '>=', '%d', $condition['value'] ), - 'olderThan' . $conditionKeySuffix => array( 'zbsc_created', '<=', '%d', $condition['value2'] ) - ) - ); - } elseif ($condition['operator'] == 'previousdays'){ - - $days_value = (int)$condition['value']; - $midnight = strtotime( "midnight" ); - $previous_days_uts = $midnight - ( ( 60 * 60 * 24 ) * $days_value ); - - return array('additionalWhereArr'=> - array( - 'newerThanPreviousDays' . $conditionKeySuffix => array( 'zbsc_created', '<=', '%d', time() ), - 'olderThanPreviousDays' . $conditionKeySuffix => array( 'zbsc_created', '>=', '%d', $previous_days_uts ) - ) - ); - } - - break; - - case 'datelastcontacted': // 'before','after','daterange','datetimerange','beforeequal','afterequal','previousdays' - - // contactedAfter - if ($condition['operator'] == 'before') // datetime - return array('additionalWhereArr'=> - array('contactedBefore'.$conditionKeySuffix=>array('zbsc_lastcontacted','<','%d',$condition['value'])) - ); - elseif ($condition['operator'] == 'beforeequal') // date - return array('additionalWhereArr'=> - array( 'contactedBeforeEqual' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '<=', '%d', $condition['value'] ) ) - ); - elseif ($condition['operator'] == 'after') //datetime - return array('additionalWhereArr'=> - array('contactedAfter'.$conditionKeySuffix=>array('zbsc_lastcontacted','>','%d',$condition['value'])) - ); - elseif ($condition['operator'] == 'afterequal') // date - return array('additionalWhereArr'=> - array( 'contactedAfterEqual' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '>=', '%d', $condition['value'] ) ) - ); - elseif ( - $condition['operator'] == 'daterange' - || - $condition['operator'] == 'datetimerange' - ){ - - $before = false; $after = false; - // split out the value - if (isset($condition['value']) && !empty($condition['value'])) $after = (int)$condition['value']; - if (isset($condition['value2']) && !empty($condition['value2'])) $before = (int)$condition['value2']; - - // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: - // return array('contactedAfter'=>$after,'contactedBefore'=>$before); - return array('additionalWhereArr'=> - array( - 'contactedAfter'.$conditionKeySuffix=>array('zbsc_lastcontacted','>=','%d',$after), - 'contactedBefore'.$conditionKeySuffix=>array('zbsc_lastcontacted','<=','%d',$before) - ) - ); - } elseif ( $condition['operator'] == 'previousdays' ){ - - $days_value = (int)$condition['value']; - $previous_days_uts = strtotime( "-" . $days_value . " days" ); - - return array('additionalWhereArr'=> - array( - 'contactedAfterPreviousDays' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '<=', '%d', time() ), - 'contactedBeforePreviousDays' . $conditionKeySuffix => array( 'zbsc_lastcontacted', '>=', '%d', $previous_days_uts ) - ) - ); - } - - break; - - case 'tagged': // 'tag' - - // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: - // return array('isTagged'=>$condition['value']); - // NOTE - // ... this is a DIRECT query, so format for adding here is a little diff - // ... and only works (not overriding existing ['direct']) because the calling func of this func has to especially copy separately - return array('additionalWhereArr'=> - array('direct' => array( - array('(SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = contact.ID AND zbstl_tagid = %d) > 0',array(ZBS_TYPE_CONTACT,$condition['value'])) - ) - ) - ); - - break; - - case 'nottagged': // 'tag' - - // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: - // return array('isNotTagged'=>$condition['value']); - - // NOTE - // ... this is a DIRECT query, so format for adding here is a little diff - // ... and only works (not overriding existing ['direct']) because the calling func of this func has to especially copy separately - return array('additionalWhereArr'=> - array('direct' => array( - array('(SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = contact.ID AND zbstl_tagid = %d) = 0',array(ZBS_TYPE_CONTACT,$condition['value'])) - ) - ) - ); - break; + case 'nottagged': // 'tag' + // while this is right, it doesn't allow for MULTIPLE status cond lines, so do via sql: + // return array('isNotTagged'=>$condition['value']); + + // NOTE + // ... this is a DIRECT query, so format for adding here is a little diff + // ... and only works (not overriding existing ['direct']) because the calling func of this func has to especially copy separately + return array( + 'additionalWhereArr' => + array( + 'direct' => array( + array( '(SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = contact.ID AND zbstl_tagid = %d) = 0', array( ZBS_TYPE_CONTACT, $condition['value'] ) ), + ), + ), + ); + break; default: break; @@ -1697,180 +1792,169 @@ public function segmentConditionArgs($condition=array(),$conditionKeySuffix=''){ } } - // if we get here we've failed to create any arguments for this condiition - // ... to avoid scenarios such as mail campaigns going out to 'less filtered than intended' audiences - // ... we throw an error - $this->error_condition_exception( - 'segment_condition_produces_no_args', - __( 'Segment Condition produces no filtering arguments', 'zero-bs-crm'), - array( 'condition' => $condition ) - ); - - return false; - - } - - // ONLY USED FOR SEGMENT SQL BUILING CURRENTLY, deep. - // ----------------------- - // This was required to work with OR (e.g. postcode 1 = x or postcode 2 = x) - // ----------------------- - // This generates a query like 'zbsc_fname LIKE %s OR zbsc_lname LIKE %s', - // which we then need to include as direct subquery - public function segmentBuildDirectOrClause($directQueries=array(),$andOr='OR'){ - /* this works, in segmentConditionArgs(), adapted below to fit generic func to keep it DRY - $conditionQArr = $this->buildWheres(array( - 'email'.$conditionKeySuffix=>array('zbsc_email','=','%s',$condition['value']), - 'emailAKA'.$conditionKeySuffix=>array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$condition['value']) - ),'',array(),'OR',false); - if (is_array($conditionQArr) && isset($conditionQArr['where']) && !empty($conditionQArr['where'])){ - return array('additionalWhereArr'=>array('direct'=>array(array('('.$conditionQArr['where'].')',$conditionQArr['params'])))); - } - return array(); + // if we get here we've failed to create any arguments for this condiition + // ... to avoid scenarios such as mail campaigns going out to 'less filtered than intended' audiences + // ... we throw an error + $this->error_condition_exception( + 'segment_condition_produces_no_args', + __( 'Segment Condition produces no filtering arguments', 'zero-bs-crm' ), + array( 'condition' => $condition ) + ); - */ - $directArr = $this->buildWheres($directQueries,'',array(),$andOr,false); - if (is_array($directArr) && isset($directArr['where']) && !empty($directArr['where'])){ - return array('additionalWhereArr'=>array('direct'=>array(array('('.$directArr['where'].')',$directArr['params'])))); - } - return array(); - } - - - /** - * Compile a segment () - */ - public function compileSegment($segmentID=-1){ - - if ( !empty( $segmentID ) ) { - - // 'GET' the segment count without paging limits - // ... this func then automatically updates the compile record, so nothing to do :) - return $this->getSegementAudience($segmentID,-1,-1,'ID','DESC',true); - - } + return false; + } - return false; - - } - - /** - * Throw an exception - */ - protected function error_condition_exception($code, $message, $data){ - - throw new Segment_Condition_Exception( $code, $message, $data ); - - } - - - - /** - * Checks that a segment audience can be compiled or if it has any outstanding errors - * ... returning as a string if so. - * ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack - */ - public function segment_error( $segment_id ){ - - global $zbs; + // ONLY USED FOR SEGMENT SQL BUILING CURRENTLY, deep. + // ----------------------- + // This was required to work with OR (e.g. postcode 1 = x or postcode 2 = x) + // ----------------------- + // This generates a query like 'zbsc_fname LIKE %s OR zbsc_lname LIKE %s', + // which we then need to include as direct subquery + public function segmentBuildDirectOrClause( $directQueries = array(), $andOr = 'OR' ) { + /* + this works, in segmentConditionArgs(), adapted below to fit generic func to keep it DRY + $conditionQArr = $this->buildWheres(array( + 'email'.$conditionKeySuffix=>array('zbsc_email','=','%s',$condition['value']), + 'emailAKA'.$conditionKeySuffix=>array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$condition['value']) + ),'',array(),'OR',false); + if (is_array($conditionQArr) && isset($conditionQArr['where']) && !empty($conditionQArr['where'])){ + return array('additionalWhereArr'=>array('direct'=>array(array('('.$conditionQArr['where'].')',$conditionQArr['params'])))); + } + return array(); - // sanitise and check - $segment_id = (int)$segment_id; - if ( $segment_id <= 0 ) return ''; + */ + $directArr = $this->buildWheres( $directQueries, '', array(), $andOr, false ); + if ( is_array( $directArr ) && isset( $directArr['where'] ) && ! empty( $directArr['where'] ) ) { + return array( 'additionalWhereArr' => array( 'direct' => array( array( '(' . $directArr['where'] . ')', $directArr['params'] ) ) ) ); + } + return array(); + } - // Retrieve any setting value - return $zbs->settings->get( 'segment-error-' . $segment_id ); + /** + * Compile a segment () + */ + public function compileSegment( $segmentID = -1 ) { - } + if ( ! empty( $segmentID ) ) { - /** - * Updates any stored segment audience error - * ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack - */ - public function add_segment_error( $segment_id, $error_string ){ - - global $zbs; + // 'GET' the segment count without paging limits + // ... this func then automatically updates the compile record, so nothing to do :) + return $this->getSegementAudience( $segmentID, -1, -1, 'ID', 'DESC', true ); - // sanitise and check - $segment_id = (int)$segment_id; - if ( $segment_id <= 0 ) return false; + } - // Set segment area error notice - $zbs->settings->update( 'segment-error-' . $segment_id, $error_string ); + return false; + } + + /** + * Throw an exception + */ + protected function error_condition_exception( $code, $message, $data ) { + + throw new Segment_Condition_Exception( $code, $message, $data ); + } - } + /** + * Checks that a segment audience can be compiled or if it has any outstanding errors + * ... returning as a string if so. + * ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack + */ + public function segment_error( $segment_id ) { + global $zbs; - /** - * Removes any stored segment audience error - * ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack - */ - public function remove_segment_error( $segment_id ){ - - global $zbs; + // sanitise and check + $segment_id = (int) $segment_id; + if ( $segment_id <= 0 ) { + return ''; + } - // sanitise and check - $segment_id = (int)$segment_id; - if ( $segment_id <= 0 ) return false; + // Retrieve any setting value + return $zbs->settings->get( 'segment-error-' . $segment_id ); + } - // Remove any segment area error notice - $zbs->settings->delete( 'segment-error-' . $segment_id ); + /** + * Updates any stored segment audience error + * ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack + */ + public function add_segment_error( $segment_id, $error_string ) { - } + global $zbs; + // sanitise and check + $segment_id = (int) $segment_id; + if ( $segment_id <= 0 ) { + return false; + } - /** - * Flags up a segment error where a used condition was missing in building a segment - * - * @param int - Segment ID - * @param Exception - the related exception - */ - public function segment_error_condition_missing( $segmentID, $exception ){ + // Set segment area error notice + $zbs->settings->update( 'segment-error-' . $segment_id, $error_string ); + } - // Not all conditions were able to produce arguments - // Here we are best to return an empty audience and alert the admin - // e.g. building a segment for a mail campaign without all conditions - // and sending to a larger-than-expected audience is more dangerous than sending to zero. - $error_string = $exception->get_error_code(); + /** + * Removes any stored segment audience error + * ... for now this is done via a setting, later we should build an error stack via DAL #refined-error-stack + */ + public function remove_segment_error( $segment_id ) { - // Set an admin notification to warn admin (max once every 2 days) - $transient_flag = get_transient( 'crm-segment-condition-missing-arg' ); - if ( !$transient_flag ){ + global $zbs; - // insert notification - zeroBSCRM_notifyme_insert_notification( get_current_user_id(), -999, -1, 'segments.orphaned.conditions', 'segmentconditionmissing' ); - - // set transient - set_transient( 'crm-segment-condition-missing-arg', 1, 24 * 2 * HOUR_IN_SECONDS ); + // sanitise and check + $segment_id = (int) $segment_id; + if ( $segment_id <= 0 ) { + return false; + } - } + // Remove any segment area error notice + $zbs->settings->delete( 'segment-error-' . $segment_id ); + } - // Set segment area error notice - $this->add_segment_error( $segmentID, $error_string ); - } + /** + * Flags up a segment error where a used condition was missing in building a segment + * + * @param int - Segment ID + * @param Exception - the related exception + */ + public function segment_error_condition_missing( $segmentID, $exception ) { + // Not all conditions were able to produce arguments + // Here we are best to return an empty audience and alert the admin + // e.g. building a segment for a mail campaign without all conditions + // and sending to a larger-than-expected audience is more dangerous than sending to zero. + $error_string = $exception->get_error_code(); - /** - * Migrates a superseded condition in the db to an up to date condition key - * - * @param string $superseded_key - the key of the old condition which has been replaced - * @param string $new_key - the key to replace it with - */ - public function migrate_superseded_condition( $superseded_key, $new_key ){ + // Set an admin notification to warn admin (max once every 2 days) + $transient_flag = get_transient( 'crm-segment-condition-missing-arg' ); + if ( ! $transient_flag ) { - global $zbs, $ZBSCRM_t, $wpdb; + // insert notification + zeroBSCRM_notifyme_insert_notification( get_current_user_id(), -999, -1, 'segments.orphaned.conditions', 'segmentconditionmissing' ); - // very short and brutal. Ignores any ownership - $query = "UPDATE " . $ZBSCRM_t['segmentsconditions'] . " SET zbscondition_type = %s WHERE zbscondition_type = %s"; - $q = $wpdb->prepare( $query, array( $new_key, $superseded_key ) ); - return $wpdb->query( $q ); + // set transient + set_transient( 'crm-segment-condition-missing-arg', 1, 24 * 2 * HOUR_IN_SECONDS ); - } + } + // Set segment area error notice + $this->add_segment_error( $segmentID, $error_string ); + } + /** + * Migrates a superseded condition in the db to an up to date condition key + * + * @param string $superseded_key - the key of the old condition which has been replaced + * @param string $new_key - the key to replace it with + */ + public function migrate_superseded_condition( $superseded_key, $new_key ) { + global $zbs, $ZBSCRM_t, $wpdb; - + // very short and brutal. Ignores any ownership + $query = 'UPDATE ' . $ZBSCRM_t['segmentsconditions'] . ' SET zbscondition_type = %s WHERE zbscondition_type = %s'; + $q = $wpdb->prepare( $query, array( $new_key, $superseded_key ) ); + return $wpdb->query( $q ); + } - // =========== / SEGMENTS =================================================== - // =============================================================================== + // =========== / SEGMENTS =================================================== + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Transactions.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Transactions.php index 00e6d7c89085..bf7fdc6f53fa 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Transactions.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Transactions.php @@ -1,5 +1,6 @@ -> Transactions -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Transactions + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_transactions extends zbsDAL_ObjectLayer { - - protected $objectType = ZBS_TYPE_TRANSACTION; - protected $objectDBPrefix = 'zbst_'; + protected $objectType = ZBS_TYPE_TRANSACTION; + protected $objectDBPrefix = 'zbst_'; protected $include_in_templating = true; - protected $objectModel = array( + protected $objectModel = array( // ID - 'ID' => array('fieldname' => 'ID', 'format' => 'int'), + 'ID' => array( + 'fieldname' => 'ID', + 'format' => 'int', + ), // site + team generics - 'zbs_site' => array('fieldname' => 'zbs_site', 'format' => 'int'), - 'zbs_team' => array('fieldname' => 'zbs_team', 'format' => 'int'), - 'zbs_owner'=> array('fieldname' => 'zbs_owner', 'format' => 'int'), + 'zbs_site' => array( + 'fieldname' => 'zbs_site', + 'format' => 'int', + ), + 'zbs_team' => array( + 'fieldname' => 'zbs_team', + 'format' => 'int', + ), + 'zbs_owner' => array( + 'fieldname' => 'zbs_owner', + 'format' => 'int', + ), // other fields - 'status' => array( - // db model: - 'fieldname' => 'zbst_status', 'format' => 'str', - // output model - 'input_type' => 'select', - 'label' => 'Status', - 'placeholder'=>'', - 'options'=>array('Succeeded','Completed','Failed','Refunded','Processing','Pending','Hold','Cancelled'), - 'essential' => true, - 'max_len' => 50 + 'status' => array( + // db model: + 'fieldname' => 'zbst_status', + 'format' => 'str', + // output model + 'input_type' => 'select', + 'label' => 'Status', + 'placeholder' => '', + 'options' => array( 'Succeeded', 'Completed', 'Failed', 'Refunded', 'Processing', 'Pending', 'Hold', 'Cancelled' ), + 'essential' => true, + 'max_len' => 50, ), - 'type' => array( - // db model: - 'fieldname' => 'zbst_type', 'format' => 'str', - // output model - 'input_type' => 'select', - 'label' => 'Type', - 'placeholder'=>'', - 'options'=>array('Sale','Refund','Credit Note'), - 'essential' => true, - 'default' => 'Sale', - 'max_len' => 50 + 'type' => array( + // db model: + 'fieldname' => 'zbst_type', + 'format' => 'str', + // output model + 'input_type' => 'select', + 'label' => 'Type', + 'placeholder' => '', + 'options' => array( 'Sale', 'Refund', 'Credit Note' ), + 'essential' => true, + 'default' => 'Sale', + 'max_len' => 50, ), 'ref' => array( - // db model: - 'fieldname' => 'zbst_ref', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Transaction ID', - 'placeholder'=>'', - 'essential' => true, - 'dal1key' => 'orderid', - 'force_unique' => true, // must be unique. This is required and breaking if true, - 'not_empty' => true, - 'max_len' => 120 + // db model: + 'fieldname' => 'zbst_ref', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Transaction ID', + 'placeholder' => '', + 'essential' => true, + 'dal1key' => 'orderid', + 'force_unique' => true, // must be unique. This is required and breaking if true, + 'not_empty' => true, + 'max_len' => 120, ), - 'origin' => array( + 'origin' => array( 'fieldname' => 'zbst_origin', - 'format' => 'str', - 'max_len' => 100 + 'format' => 'str', + 'max_len' => 100, ), - 'parent' => array('fieldname' => 'zbst_parent', 'format' => 'int'), - 'hash' => array('fieldname' => 'zbst_hash', 'format' => 'str'), - 'title' => array( - // db model: - 'fieldname' => 'zbst_title', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Transaction Title', - 'placeholder' => 'e.g. Product ABC', - 'dal1key' => 'item', - 'max_len' => 200 + 'parent' => array( + 'fieldname' => 'zbst_parent', + 'format' => 'int', + ), + 'hash' => array( + 'fieldname' => 'zbst_hash', + 'format' => 'str', + ), + 'title' => array( + // db model: + 'fieldname' => 'zbst_title', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Transaction Title', + 'placeholder' => 'e.g. Product ABC', + 'dal1key' => 'item', + 'max_len' => 200, ), - 'desc' => array( - // db model: - 'fieldname' => 'zbst_desc', 'format' => 'str', - // output model - 'input_type' => 'textarea', - 'label' => 'Description', - 'placeholder' => '', - 'max_len' => 200 + 'desc' => array( + // db model: + 'fieldname' => 'zbst_desc', + 'format' => 'str', + // output model + 'input_type' => 'textarea', + 'label' => 'Description', + 'placeholder' => '', + 'max_len' => 200, ), - 'date' => array( - // db model: - 'fieldname' => 'zbst_date', 'format' => 'uts', - 'autoconvert'=>'datetime', // NOTE autoconvert makes buildObjArr autoconvert from a 'date' using localisation rules, to a GMT timestamp (UTS) + 'date' => array( + // db model: + 'fieldname' => 'zbst_date', + 'format' => 'uts', + 'autoconvert' => 'datetime', // NOTE autoconvert makes buildObjArr autoconvert from a 'date' using localisation rules, to a GMT timestamp (UTS) // output model - 'input_type' => 'datetime', - 'label' => 'Transaction Date', - 'placeholder'=>'' + 'input_type' => 'datetime', + 'label' => 'Transaction Date', + 'placeholder' => '', ), // <-- this is a bit of a misnomer, it's basically timestamp for created - 'customer_ip' => array( + 'customer_ip' => array( 'fieldname' => 'zbst_customer_ip', - 'format' => 'str', - 'max_len' => 45 + 'format' => 'str', + 'max_len' => 45, ), - 'currency' => array( + 'currency' => array( 'fieldname' => 'zbst_currency', - 'format' => 'curr', - 'max_len' => 4 + 'format' => 'curr', + 'max_len' => 4, ), 'net' => array( - // db model: - 'fieldname' => 'zbst_net', 'format' => 'decimal', - // output model - 'input_type' => 'price', - 'label' => 'Net', - 'placeholder'=>'', - 'default' => '0.00' + // db model: + 'fieldname' => 'zbst_net', + 'format' => 'decimal', + // output model + 'input_type' => 'price', + 'label' => 'Net', + 'placeholder' => '', + 'default' => '0.00', ), 'fee' => array( // db model: - 'fieldname' => 'zbst_fee', 'format' => 'decimal', + 'fieldname' => 'zbst_fee', + 'format' => 'decimal', // output model - 'input_type' => 'price', - 'label' => 'Fee', - 'placeholder'=>'', - 'default' => '0.00' + 'input_type' => 'price', + 'label' => 'Fee', + 'placeholder' => '', + 'default' => '0.00', ), - 'discount' => array( - // db model: - 'fieldname' => 'zbst_discount', 'format' => 'decimal', - // output model - 'input_type' => 'price', - 'label' => 'Discount', - 'placeholder'=>'', - 'default' => '0.00' + 'discount' => array( + // db model: + 'fieldname' => 'zbst_discount', + 'format' => 'decimal', + // output model + 'input_type' => 'price', + 'label' => 'Discount', + 'placeholder' => '', + 'default' => '0.00', ), - 'shipping' => array( - // db model: - 'fieldname' => 'zbst_shipping', 'format' => 'decimal', - // output model - 'input_type' => 'price', - 'label' => 'Shipping', - 'placeholder'=>'', - 'default' => '0.00' + 'shipping' => array( + // db model: + 'fieldname' => 'zbst_shipping', + 'format' => 'decimal', + // output model + 'input_type' => 'price', + 'label' => 'Shipping', + 'placeholder' => '', + 'default' => '0.00', ), - 'shipping_taxes' => array( - // db model: - 'fieldname' => 'zbst_shipping_taxes', 'format' => 'str', - // output model - 'input_type' => 'tax', - 'label' => 'Shipping Taxes', - 'placeholder'=>'' + 'shipping_taxes' => array( + // db model: + 'fieldname' => 'zbst_shipping_taxes', + 'format' => 'str', + // output model + 'input_type' => 'tax', + 'label' => 'Shipping Taxes', + 'placeholder' => '', ), - 'shipping_tax' => array('fieldname' => 'zbst_shipping_tax', 'format' => 'decimal', 'label' => 'Shipping Tax',), - 'taxes' => array( - // db model: - 'fieldname' => 'zbst_taxes', - 'format' => 'str', - // output model - 'input_type' => 'tax', - 'label' => 'Taxes', - 'placeholder'=>'' - - // replaces tax_rate, but tax_rate was a decimal, this is a string of applicable tax codes from tax table. + 'shipping_tax' => array( + 'fieldname' => 'zbst_shipping_tax', + 'format' => 'decimal', + 'label' => 'Shipping Tax', + ), + 'taxes' => array( + // db model: + 'fieldname' => 'zbst_taxes', + 'format' => 'str', + // output model + 'input_type' => 'tax', + 'label' => 'Taxes', + 'placeholder' => '', + + // replaces tax_rate, but tax_rate was a decimal, this is a string of applicable tax codes from tax table. ), - 'tax' => array( - 'fieldname' => 'zbst_tax', - 'format' => 'decimal', - 'label' => 'Tax', - 'input_type' => 'price', - 'placeholder'=>'', + 'tax' => array( + 'fieldname' => 'zbst_tax', + 'format' => 'decimal', + 'label' => 'Tax', + 'input_type' => 'price', + 'placeholder' => '', ), - 'total' => array( - // db model: - 'fieldname' => 'zbst_total', 'format' => 'decimal', - // output model - 'input_type' => 'price', - 'label' => 'Total', - 'placeholder'=>'', - 'default' => '0.00', - 'essential' => true + 'total' => array( + // db model: + 'fieldname' => 'zbst_total', + 'format' => 'decimal', + // output model + 'input_type' => 'price', + 'label' => 'Total', + 'placeholder' => '', + 'default' => '0.00', + 'essential' => true, ), - 'date_paid' => array( - // db model: - 'fieldname' => 'zbst_date_paid', 'format' => 'uts', - 'autoconvert'=>'date', // NOTE autoconvert makes buildObjArr autoconvert from a 'date' using localisation rules, to a GMT timestamp (UTS) + 'date_paid' => array( + // db model: + 'fieldname' => 'zbst_date_paid', + 'format' => 'uts', + 'autoconvert' => 'date', // NOTE autoconvert makes buildObjArr autoconvert from a 'date' using localisation rules, to a GMT timestamp (UTS) // output model - 'input_type' => 'date', - 'label' => 'Date Paid', + 'input_type' => 'date', + 'label' => 'Date Paid', ), - 'date_completed' => array( - // db model: - 'fieldname' => 'zbst_date_completed', 'format' => 'uts', - 'autoconvert'=>'date', // NOTE autoconvert makes buildObjArr autoconvert from a 'date' using localisation rules, to a GMT timestamp (UTS) + 'date_completed' => array( + // db model: + 'fieldname' => 'zbst_date_completed', + 'format' => 'uts', + 'autoconvert' => 'date', // NOTE autoconvert makes buildObjArr autoconvert from a 'date' using localisation rules, to a GMT timestamp (UTS) // output model - 'input_type' => 'date', - 'label' => 'Date Completed' + 'input_type' => 'date', + 'label' => 'Date Completed', ), - 'created' => array('fieldname' => 'zbst_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbst_lastupdated', 'format' => 'uts'), - - ); + 'created' => array( + 'fieldname' => 'zbst_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbst_lastupdated', + 'format' => 'uts', + ), + ); // hardtyped list of types this object type is commonly linked to protected $linkedToObjectTypes = array( ZBS_TYPE_CONTACT, - ZBS_TYPE_COMPANY + ZBS_TYPE_COMPANY, ); @@ -234,21 +275,34 @@ class zbsDAL_transactions extends zbsDAL_ObjectLayer { */ private $events_manager; - function __construct($args=array()) { - + function __construct( $args = array() ) { - #} =========== LOAD ARGS ============== - $defaultArgs = array( + #} =========== LOAD ARGS ============== + $defaultArgs = array( - //'tag' => false, + // 'tag' => false, - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= $this->events_manager = new Events_Manager(); add_filter( 'jpcrm_listview_filters', array( $this, 'add_listview_filters' ) ); - } + } /** * Adds items to listview filter using `jpcrm_listview_filters` hook. @@ -267,155 +321,176 @@ public function add_listview_filters( $listview_filters ) { return $listview_filters; } - // =============================================================================== - // =========== TRANSACTION ======================================================= - - // generic get Company (by ID) - // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) - public function getSingle($ID=-1){ - - return $this->getTransaction($ID); - - } - - // generic get (by ID list) - // Super simplistic wrapper used by MVP Export v3.0 - public function getIDList($IDs=false){ - - return $this->getTransactions(array( - 'inArr' => $IDs, - 'withOwner' => true, - 'withAssigned' => true, - 'page' => -1, - 'perPage' => -1 - )); - - } - - // generic get (EVERYTHING) - // expect heavy load! - public function getAll($IDs=false){ - - return $this->getTransactions(array( - 'withOwner' => true, - 'withAssigned' => true, - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => -1, - 'perPage' => -1, - )); - - } - - // generic get count of (EVERYTHING) - public function getFullCount(){ - - return $this->getTransactions(array( - 'count' => true, - 'page' => -1, - 'perPage' => -1, - )); - - } - - /** - * Verifies there is a transaction with this ID accessible to current logged in user - * - * @param int transaction_id - * - * @return bool - */ - public function transaction_exists( $transaction_id ){ - - // has to be a legit int - if ( empty( $transaction_id ) ){ - return false; - } - - // note this ignores ownership for now - $potential_transaction = $this->getTransaction( $transaction_id, array( 'onlyID' => true ) ); - - if ( $potential_transaction > 0 ){ - - return true; - - } - - return false; - - } - - /** - * returns full transaction line +- details - * - * @param int id transaction id - * @param array $args Associative array of arguments - * - * @return array transaction object - */ - public function getTransaction($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - // if these two passed, will search based on these - 'externalSource' => false, - 'externalSourceUID' => false, - - // with what? - 'withLineItems' => true, - 'withCustomFields' => true, - 'withAssigned' => true, // return ['contact'] & ['company'] arrays, & invoice_id field, if has link - 'withTags' => false, - 'withOwner' => false, + // =============================================================================== + // =========== TRANSACTION ======================================================= - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION), // this'll let you not-check the owner of obj + // generic get Company (by ID) + // Super simplistic wrapper used by edit page etc. (generically called via dal->contacts->getSingle etc.) + public function getSingle( $ID = -1 ) { - // returns scalar ID of line - 'onlyID' => false, + return $this->getTransaction( $ID ); + } + + // generic get (by ID list) + // Super simplistic wrapper used by MVP Export v3.0 + public function getIDList( $IDs = false ) { + + return $this->getTransactions( + array( + 'inArr' => $IDs, + 'withOwner' => true, + 'withAssigned' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } - 'fields' => false // false = *, array = fieldnames + // generic get (EVERYTHING) + // expect heavy load! + public function getAll( $IDs = false ) { + + return $this->getTransactions( + array( + 'withOwner' => true, + 'withAssigned' => true, + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + // generic get count of (EVERYTHING) + public function getFullCount() { + + return $this->getTransactions( + array( + 'count' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + /** + * Verifies there is a transaction with this ID accessible to current logged in user + * + * @param int transaction_id + * + * @return bool + */ + public function transaction_exists( $transaction_id ) { + + // has to be a legit int + if ( empty( $transaction_id ) ) { + return false; + } + + // note this ignores ownership for now + $potential_transaction = $this->getTransaction( $transaction_id, array( 'onlyID' => true ) ); + + if ( $potential_transaction > 0 ) { + + return true; + + } + + return false; + } + + /** + * returns full transaction line +- details + * + * @param int id transaction id + * @param array $args Associative array of arguments + * + * @return array transaction object + */ + public function getTransaction( $id = -1, $args = array() ) { + + global $zbs; + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // if these two passed, will search based on these + 'externalSource' => false, + 'externalSourceUID' => false, + + // with what? + 'withLineItems' => true, + 'withCustomFields' => true, + 'withAssigned' => true, // return ['contact'] & ['company'] arrays, & invoice_id field, if has link + 'withTags' => false, + 'withOwner' => false, + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + 'fields' => false, // false = *, array = fieldnames + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check ID - $id = (int)$id; - if ( - (!empty($id) && $id > 0) + #} Check ID + $id = (int) $id; + if ( + ( ! empty( $id ) && $id > 0 ) || - (!empty($email)) + ( ! empty( $email ) ) || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ + ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) + ) { - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $extraSelect = ''; - - #} ============= PRE-QUERY ============ + #} ============= PRE-QUERY ============ #} Custom Fields - if ($withCustomFields && !$onlyID){ - + if ( $withCustomFields && ! $onlyID ) { + #} Retrieve any cf - $custFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_TRANSACTION)); + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_TRANSACTION ) ); #} Cycle through + build into query - if (is_array($custFields)) foreach ($custFields as $cK => $cF){ + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { - // add as subquery + // add as subquery $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . " WHERE zbscf_objid = transactions.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '" . $cK . "'"; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_TRANSACTION; - } + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_TRANSACTION; - } + } + } + } $selector = 'transactions.*'; if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable @@ -434,282 +509,338 @@ public function getTransaction($id=-1,$args=array()){ } } elseif ( $onlyID ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable $selector = 'transactions.ID'; - } - - #} ============ / PRE-QUERY =========== + } + #} ============ / PRE-QUERY =========== - #} Build query + #} Build query $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - #} ============= WHERE ================ - - if (!empty($id) && $id > 0){ - - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); + #} ============= WHERE ================ - } - - if (!empty($externalSource) && !empty($externalSourceUID)){ - - $wheres['extsourcecheck'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_TRANSACTION." AND zbss_source = %s AND zbss_uid = %s)",array($externalSource,$externalSourceUID)); - - } + if ( ! empty( $id ) && $id > 0 ) { - #} ============ / WHERE ============== + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE - - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); - - try { - - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $this->catchSQLError($e); + } - } + if ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) { - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + $wheres['extsourcecheck'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_TRANSACTION . ' AND zbss_source = %s AND zbss_uid = %s)', array( $externalSource, $externalSourceUID ) ); - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID) return $potentialRes->ID; - - // tidy - if (is_array($fields)){ - // guesses fields based on table col names - $res = $this->lazyTidyGeneric($potentialRes); - } else { - // proper tidy - $res = $this->tidy_transaction($potentialRes,$withCustomFields); - } + } - if ($withLineItems){ + #} ============ / WHERE ============== - // add all line item lines - $res['lineitems'] = $this->DAL()->lineitems->getLineitems(array('associatedObjType'=>ZBS_TYPE_TRANSACTION,'associatedObjID'=>$potentialRes->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LINEITEM))); - - } + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - if ($withAssigned){ + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - /* This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - // add all assigned contacts/companies - $res['contacts'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + try { - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - .. but we use 1:1, at least now: */ + } catch ( Exception $e ) { - // add all assigned contacts/companies - $res['contact'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$potentialRes->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + #} General SQL Err + $this->catchSQLError( $e ); - $res['company'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$potentialRes->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + } - // invoice id always singular. - $res['invoice_id'] = $this->DAL()->getFirstIDLinkedToObj(array( + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - 'objtypefrom' => ZBS_TYPE_TRANSACTION, - 'objtypeto' => ZBS_TYPE_INVOICE, - 'objfromid' => $potentialRes->ID, + #} Has results, tidy + return - )); + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } - - } + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_transaction( $potentialRes, $withCustomFields ); + } - if ($withTags){ + if ( $withLineItems ) { - // add all tags lines - $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_TRANSACTION,'objid'=>$potentialRes->ID)); - - } + // add all line item lines + $res['lineitems'] = $this->DAL()->lineitems->getLineitems( + array( + 'associatedObjType' => ZBS_TYPE_TRANSACTION, + 'associatedObjID' => $potentialRes->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LINEITEM ), + ) + ); - return $res; + } - } + if ( $withAssigned ) { + + /* + This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + + // add all assigned contacts/companies + $res['contacts'] = $this->DAL()->contacts->getContacts(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + + $res['companies'] = $this->DAL()->companies->getCompanies(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + + .. but we use 1:1, at least now: */ + + // add all assigned contacts/companies + $res['contact'] = $this->DAL()->contacts->getContacts( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo' => $potentialRes->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); - } // / if ID + $res['company'] = $this->DAL()->companies->getCompanies( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo' => $potentialRes->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); - return false; + // invoice id always singular. + $res['invoice_id'] = $this->DAL()->getFirstIDLinkedToObj( + array( - } + 'objtypefrom' => ZBS_TYPE_TRANSACTION, + 'objtypeto' => ZBS_TYPE_INVOICE, + 'objfromid' => $potentialRes->ID, - /** - * Returns transaction summed by field between passed timestamps - */ - public function getTransactionTotalByMonth( $args=array() ) { + ) + ); - global $ZBSCRM_t, $wpdb, $zbs; + } - // ============ LOAD ARGS ============= - $defaultArgs = array( + if ( $withTags ) { - 'paidAfter' => strtotime( '12 month ago' ), - 'paidBefore' => time(), + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_TRANSACTION, + 'objid' => $potentialRes->ID, + ) + ); - ); - foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - // =========== / LOAD ARGS ============= + } - $column_prefix = 'zbst_'; + return $res; - // only include transactions with statuses which should be included in total value: - $transStatusQueryAdd = $this->getTransactionStatusesToIncludeQuery(); + } + } // / if ID - $sql = $wpdb->prepare( 'SELECT SUM(' . $column_prefix . 'total) as total, MONTH(FROM_UNIXTIME(' . $column_prefix . 'date)) as month, YEAR(FROM_UNIXTIME(' . $column_prefix . 'date)) as year FROM ' . $ZBSCRM_t['transactions'] . ' WHERE ' . $column_prefix . 'date > %d AND ' . $column_prefix . 'date < %d' . $transStatusQueryAdd . ' GROUP BY month, year ORDER BY year, month', $paidAfter, $paidBefore ); - $res = $wpdb->get_results( $sql, ARRAY_A ); + return false; + } - return $res; + /** + * Returns transaction summed by field between passed timestamps + */ + public function getTransactionTotalByMonth( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + // ============ LOAD ARGS ============= + $defaultArgs = array( + + 'paidAfter' => strtotime( '12 month ago' ), + 'paidBefore' => time(), + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + // =========== / LOAD ARGS ============= - } + $column_prefix = 'zbst_'; - /** - * returns transaction detail lines - * - * @param array $args Associative array of arguments - * - * @return array of transaction lines - */ - public function getTransactions($args=array()){ + // only include transactions with statuses which should be included in total value: + $transStatusQueryAdd = $this->getTransactionStatusesToIncludeQuery(); - global $ZBSCRM_t,$wpdb,$zbs; + $sql = $wpdb->prepare( 'SELECT SUM(' . $column_prefix . 'total) as total, MONTH(FROM_UNIXTIME(' . $column_prefix . 'date)) as month, YEAR(FROM_UNIXTIME(' . $column_prefix . 'date)) as year FROM ' . $ZBSCRM_t['transactions'] . ' WHERE ' . $column_prefix . 'date > %d AND ' . $column_prefix . 'date < %d' . $transStatusQueryAdd . ' GROUP BY month, year ORDER BY year, month', $paidAfter, $paidBefore ); + $res = $wpdb->get_results( $sql, ARRAY_A ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + return $res; + } - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches zbst_title and zbst_desc - 'inArr' => false, - 'isTagged' => false, // 1x INT OR array(1,2,3) - 'isNotTagged' => false, // 1x INT OR array(1,2,3) - 'ownedBy' => false, - 'externalSource' => false, // e.g. paypal - 'hasStatus' => false, // Lead (this takes over from the quick filter post 19/6/18) - 'otherStatus' => false, // status other than 'Lead' - 'assignedContact' => false, // assigned to contact id (int) - 'assignedCompany' => false, // assigned to company id (int) - 'assignedInvoice' => false, // assigned to invoice id (int) - 'quickFilters' => false, - 'external_source_uid' => false, // e.g. woo-order_10 + /** + * returns transaction detail lines + * + * @param array $args Associative array of arguments + * + * @return array of transaction lines + */ + public function getTransactions( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => '', // searches zbst_title and zbst_desc + 'inArr' => false, + 'isTagged' => false, // 1x INT OR array(1,2,3) + 'isNotTagged' => false, // 1x INT OR array(1,2,3) + 'ownedBy' => false, + 'externalSource' => false, // e.g. paypal + 'hasStatus' => false, // Lead (this takes over from the quick filter post 19/6/18) + 'otherStatus' => false, // status other than 'Lead' + 'assignedContact' => false, // assigned to contact id (int) + 'assignedCompany' => false, // assigned to company id (int) + 'assignedInvoice' => false, // assigned to invoice id (int) + 'quickFilters' => false, + 'external_source_uid' => false, // e.g. woo-order_10 // date ranges - 'olderThan' => false, // uts - checks 'date' - 'newerThan' => false, // uts - checks 'date' - 'paidBefore' => false, // uts - checks 'date_paid' - 'paidAfter' => false, // uts - checks 'date_paid' - 'createdBefore' => false, // uts - checks 'created' - 'createdAfter' => false, // uts - checks 'created' + 'olderThan' => false, // uts - checks 'date' + 'newerThan' => false, // uts - checks 'date' + 'paidBefore' => false, // uts - checks 'date_paid' + 'paidAfter' => false, // uts - checks 'date_paid' + 'createdBefore' => false, // uts - checks 'created' + 'createdAfter' => false, // uts - checks 'created' // returns - 'count' => false, - 'total' => false, // returns a summed total value of transactions (scalar) - 'withLineItems' => true, - 'withCustomFields' => true, - 'withTags' => false, - 'withOwner' => false, - 'withAssigned' => true, // return ['contact'] & ['company'] objs, & invoice_id field, if has link - 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) + 'count' => false, + 'total' => false, // returns a summed total value of transactions (scalar) + 'withLineItems' => true, + 'withCustomFields' => true, + 'withTags' => false, + 'withOwner' => false, + 'withAssigned' => true, // return ['contact'] & ['company'] objs, & invoice_id field, if has link + 'onlyColumns' => false, // if passed (array('fname','lname')) will return only those columns (overwrites some other 'return' options). NOTE: only works for base fields (not custom fields) // order by - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 100, - 'whereCase' => 'AND', // DEFAULT = AND + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 100, + 'whereCase' => 'AND', // DEFAULT = AND // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION), // this'll let you not-check the owner of obj - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), // this'll let you not-check the owner of obj + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; - #} ============= PRE-QUERY ============ + #} ============= PRE-QUERY ============ // Capitalise this - $sortOrder = strtoupper($sortOrder); + $sortOrder = strtoupper( $sortOrder ); // If just count or total, turn off any meta detail if ( $count || $total ) { $withCustomFields = false; - $withTags = false; - $withOwner = false; - $withAssigned = false; - $withLineItems = false; + $withTags = false; + $withOwner = false; + $withAssigned = false; + $withLineItems = false; - } + } #} If onlyColumns, validate - if ($onlyColumns){ + if ( $onlyColumns ) { #} onlyColumns build out a field arr - if (is_array($onlyColumns) && count($onlyColumns) > 0){ + if ( is_array( $onlyColumns ) && count( $onlyColumns ) > 0 ) { $onlyColumnsFieldArr = array(); - foreach ($onlyColumns as $col){ + foreach ( $onlyColumns as $col ) { // find db col key from field key (e.g. fname => zbsc_fname) - $dbCol = ''; if (isset($this->objectModel[$col]) && isset($this->objectModel[$col]['fieldname'])) $dbCol = $this->objectModel[$col]['fieldname']; + $dbCol = ''; + if ( isset( $this->objectModel[ $col ] ) && isset( $this->objectModel[ $col ]['fieldname'] ) ) { + $dbCol = $this->objectModel[ $col ]['fieldname']; + } - if (!empty($dbCol)){ + if ( ! empty( $dbCol ) ) { - $onlyColumnsFieldArr[$dbCol] = $col; + $onlyColumnsFieldArr[ $dbCol ] = $col; } - - } - - } + } + } // if legit cols: - if (isset($onlyColumnsFieldArr) && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + if ( isset( $onlyColumnsFieldArr ) && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { $onlyColumns = true; - + // If onlyColumns, turn off extras $withCustomFields = false; - $withTags = false; - $withOwner = false; - $withAssigned = false; - $withLineItems = false; + $withTags = false; + $withOwner = false; + $withAssigned = false; + $withLineItems = false; } else { @@ -717,49 +848,49 @@ public function getTransactions($args=array()){ $onlyColumns = false; } - - - } + } #} Custom Fields // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. - if ($withCustomFields){ - + if ( $withCustomFields ) { + #} Retrieve any cf - $custFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_TRANSACTION)); + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_TRANSACTION ) ); #} Cycle through + build into query - if (is_array($custFields)) foreach ($custFields as $cK => $cF){ + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { - // custom field (e.g. 'third name') it'll be passed here as 'third-name' - // ... problem is mysql does not like that :) so we have to chage here: - // in this case we prepend cf's with cf_ and we switch - for _ - $cKey = 'cf_'.str_replace('-','_',$cK); + // custom field (e.g. 'third name') it'll be passed here as 'third-name' + // ... problem is mysql does not like that :) so we have to chage here: + // in this case we prepend cf's with cf_ and we switch - for _ + $cKey = 'cf_' . str_replace( '-', '_', $cK ); - // we also check the $sortByField in case that's the same cf - if ($cK == $sortByField){ + // we also check the $sortByField in case that's the same cf + if ( $cK == $sortByField ) { - // sort by - $sortByField = $cKey; + // sort by + $sortByField = $cKey; - // check if sort needs any CAST (e.g. numeric): - $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); + // check if sort needs any CAST (e.g. numeric): + $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); - } + } - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = transactions.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ' . $cKey; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_TRANSACTION; + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = transactions.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ' . $cKey; - } + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_TRANSACTION; - } + } + } + } if ( $external_source_uid ) { $extraSelect .= ', external_source.external_source_uids, external_source.external_source_sources'; - $joinQ .= ' LEFT JOIN ( + $joinQ .= ' LEFT JOIN ( SELECT extsrcs.zbss_objid external_source_objid, ' . $this->DAL()->build_group_concat( 'extsrcs.zbss_uid', '\n' ) . ' AS external_source_uids, @@ -771,10 +902,10 @@ public function getTransactions($args=array()){ GROUP BY extsrcs.zbss_objid ) external_source ON transactions.ID = external_source.external_source_objid'; - $params[] = ZBS_TYPE_TRANSACTION; + $params[] = ZBS_TYPE_TRANSACTION; } - #} ============ / PRE-QUERY =========== + #} ============ / PRE-QUERY =========== #} Build query $query = 'SELECT transactions.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions' . $joinQ; @@ -784,98 +915,101 @@ public function getTransactions($args=array()){ $query = 'SELECT COUNT(transactions.ID) FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions' . $joinQ; } - #} onlyColumns override - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + #} onlyColumns override + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - $columnStr = ''; - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + $columnStr = ''; + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - if (!empty($columnStr)) $columnStr .= ','; - // this presumes str is db-safe? could do with sanitation? - $columnStr .= $colDBKey; + if ( ! empty( $columnStr ) ) { + $columnStr .= ','; + } + // this presumes str is db-safe? could do with sanitation? + $columnStr .= $colDBKey; - } + } $query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions' . $joinQ; - } + } - // $total only override - if ( $total ){ + // $total only override + if ( $total ) { $query = 'SELECT SUM(transactions.zbst_total) total FROM ' . $ZBSCRM_t['transactions'] . ' AS transactions' . $joinQ; - } + } - #} ============= WHERE ================ + #} ============= WHERE ================ #} Add Search phrase - if (!empty($searchPhrase)){ + if ( ! empty( $searchPhrase ) ) { // search? - ALL THESE COLS should probs have index of FULLTEXT in db? - $searchWheres = array(); - $searchWheres['search_ID'] = array('ID','=','%d',$searchPhrase); - $searchWheres['search_ref'] = array('zbst_ref','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_title'] = array('zbst_title','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_desc'] = array('zbst_desc','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_total'] = array('zbst_total','LIKE','%s', $searchPhrase.'%'); + $searchWheres = array(); + $searchWheres['search_ID'] = array( 'ID', '=', '%d', $searchPhrase ); + $searchWheres['search_ref'] = array( 'zbst_ref', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_title'] = array( 'zbst_title', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_desc'] = array( 'zbst_desc', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_total'] = array( 'zbst_total', 'LIKE', '%s', $searchPhrase . '%' ); if ( $external_source_uid ) { $searchWheres['search_external_source_uid'] = array( 'external_source.external_source_uids', 'LIKE', '%s', '%' . $searchPhrase . '%' ); } // 3.0.13 - Added ability to search custom fields (optionally) - $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); - if ($customFieldSearch == 1){ - + $customFieldSearch = zeroBSCRM_getSetting( 'customfieldsearch' ); + if ( $customFieldSearch == 1 ) { + // simplistic add // NOTE: This IGNORES ownership of custom field lines. - $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE zbscf_objval LIKE %s AND zbscf_objtype = ".ZBS_TYPE_TRANSACTION.")",'%'.$searchPhrase.'%'); + $searchWheres['search_customfields'] = array( 'ID', 'IN', '(SELECT zbscf_objid FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objval LIKE %s AND zbscf_objtype = ' . ZBS_TYPE_TRANSACTION . ')', '%' . $searchPhrase . '%' ); } - // This generates a query like 'zbst_fname LIKE %s OR zbst_lname LIKE %s', + // This generates a query like 'zbst_fname LIKE %s OR zbst_lname LIKE %s', // which we then need to include as direct subquery (below) in main query :) - $searchQueryArr = $this->buildWheres($searchWheres,'',array(),'OR',false); - - if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ + $searchQueryArr = $this->buildWheres( $searchWheres, '', array(), 'OR', false ); + + if ( is_array( $searchQueryArr ) && isset( $searchQueryArr['where'] ) && ! empty( $searchQueryArr['where'] ) ) { // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + $wheres['direct'][] = array( '(' . $searchQueryArr['where'] . ')', $searchQueryArr['params'] ); } - - } + } #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) - if (is_array($inArr) && count($inArr) > 0){ + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { // clean for ints - $inArrChecked = array(); foreach ($inArr as $x){ $inArrChecked[] = (int)$x; } + $inArrChecked = array(); + foreach ( $inArr as $x ) { + $inArrChecked[] = (int) $x; } // add where - $wheres['inarray'] = array('ID','IN','('.implode(',',$inArrChecked).')'); + $wheres['inarray'] = array( 'ID', 'IN', '(' . implode( ',', $inArrChecked ) . ')' ); - } + } #} Owned by - if (!empty($ownedBy) && $ownedBy > 0){ - + if ( ! empty( $ownedBy ) && $ownedBy > 0 ) { + // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) // but this is only here until MIGRATED to db2 globally - //$wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); - // Use obj links now - $wheres['ownedBy'] = array('zbs_owner','=','%s',$ownedBy); + // $wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); + // Use obj links now + $wheres['ownedBy'] = array( 'zbs_owner', '=', '%s', $ownedBy ); - } + } // External sources - if ( !empty( $externalSource ) ){ + if ( ! empty( $externalSource ) ) { // NO owernship built into this, check when roll out multi-layered ownsership - $wheres['externalsource'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_TRANSACTION." AND zbss_source = %s)",$externalSource); + $wheres['externalsource'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_TRANSACTION . ' AND zbss_source = %s)', $externalSource ); - } + } // Timestamp checks: // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed @@ -904,10 +1038,10 @@ public function getTransactions($args=array()){ if ( ! empty( $assignedInvoice ) && $assignedInvoice > 0 ) $wheres['assignedInvoice'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objid_to = %d)', $assignedInvoice ); #} Quick filters - adapted from DAL1 (probs can be slicker) - if (is_array($quickFilters) && count($quickFilters) > 0){ + if ( is_array( $quickFilters ) && count( $quickFilters ) > 0 ) { // cycle through - foreach ($quickFilters as $qFilter){ + foreach ( $quickFilters as $qFilter ) { // where status = x // USE hasStatus above now... @@ -923,14 +1057,13 @@ public function getTransactions($args=array()){ $wheres = apply_filters( 'jpcrm_transaction_query_quickfilter', $wheres, $qFilter ); } - } - - }// / quickfilters + } + }// / quickfilters #} Is Tagged (expects 1 tag ID OR array) // catch 1 item arr - if (is_array($isTagged) && count($isTagged) == 1) $isTagged = $isTagged[0]; + if (is_array( $isTagged ) && count( $isTagged ) == 1) $isTagged = $isTagged[0]; if ( ! empty( $isTagged ) && ! is_array( $isTagged ) && $isTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -941,19 +1074,19 @@ public function getTransactions($args=array()){ array( ZBS_TYPE_TRANSACTION, $isTagged ), ); - } else if (is_array($isTagged) && count($isTagged) > 0){ + } elseif ( is_array( $isTagged ) && count( $isTagged ) > 0 ) { - // foreach in array :) + // foreach in array :) $tagStr = ''; - foreach ($isTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + foreach ( $isTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - if ($tagStr !== '') $tagStr .','; + if ($tagStr !== '') $tagStr . ','; $tagStr .= $i; } } - if (!empty($tagStr)){ + if ( ! empty( $tagStr ) ) { $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid IN (%s)) > 0)', @@ -961,54 +1094,50 @@ public function getTransactions($args=array()){ ); } - - } + } #} Is NOT Tagged (expects 1 tag ID OR array) // catch 1 item arr - if (is_array($isNotTagged) && count($isNotTagged) == 1) $isNotTagged = $isNotTagged[0]; - - if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - // add where tagged - // 1 int: - $wheres['direct'][] = array( - '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid = %d) = 0)', - array( ZBS_TYPE_TRANSACTION, $isNotTagged ), - ); + if (is_array( $isNotTagged ) && count( $isNotTagged ) == 1) $isNotTagged = $isNotTagged[0]; - } else if (is_array($isNotTagged) && count($isNotTagged) > 0){ + if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // foreach in array :) - $tagStr = ''; - foreach ($isNotTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + // add where tagged + // 1 int: + $wheres['direct'][] = array( + '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid = %d) = 0)', + array( ZBS_TYPE_TRANSACTION, $isNotTagged ), + ); - if ($tagStr !== '') $tagStr .','; - $tagStr .= $i; - } - } - if (!empty($tagStr)){ + } elseif ( is_array( $isNotTagged ) && count( $isNotTagged ) > 0 ) { - $wheres['direct'][] = array( - '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid IN (%s)) = 0)', - array( ZBS_TYPE_TRANSACTION, $tagStr ), - ); + // foreach in array :) + $tagStr = ''; + foreach ( $isNotTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - } + if ($tagStr !== '') $tagStr . ','; + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( + '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = transactions.ID AND zbstl_tagid IN (%s)) = 0)', + array( ZBS_TYPE_TRANSACTION, $tagStr ), + ); - + } + } - #} ============ / WHERE =============== + #} ============ / WHERE =============== - #} ============ SORT ============== + #} ============ SORT ============== // Obj Model based sort conversion // converts 'addr1' => 'zbsco_addr1' generically - if (isset($this->objectModel[$sortByField]) && isset($this->objectModel[$sortByField]['fieldname'])) $sortByField = $this->objectModel[$sortByField]['fieldname']; + if (isset( $this->objectModel[ $sortByField ] ) && isset( $this->objectModel[ $sortByField ]['fieldname'] )) $sortByField = $this->objectModel[ $sortByField ]['fieldname']; // Mapped sorts // This catches listview and other exception sort cases @@ -1018,1579 +1147,1669 @@ public function getTransactions($args=array()){ 'customer' => '(SELECT ID FROM ' . $ZBSCRM_t['contacts'] . ' WHERE ID IN (SELECT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_from = transactions.ID))', ); - - if ( array_key_exists( $sortByField, $sort_map ) ) { - $sortByField = $sort_map[ $sortByField ]; + if ( array_key_exists( $sortByField, $sort_map ) ) { - } + $sortByField = $sort_map[ $sortByField ]; - if ( $external_source_uid && $sortByField === "external_source" ){ - $sortByField = ["external_source_uids" => $sortOrder]; - } + } - #} ============ / SORT ============== + if ( $external_source_uid && $sortByField === 'external_source' ) { + $sortByField = array( 'external_source_uids' => $sortOrder ); + } - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; + #} ============ / SORT ============== - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} CHECK this + reset to default if faulty + if ( ! in_array( $whereCase, array( 'AND', 'OR' ) )) $whereCase = 'AND'; - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner,'contact'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params, $whereCase ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'contact' ); + if ( ! empty( $ownQ )) $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + #} / Ownership - try { + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); + try { - // Catch count/total + return if requested - if ( $count || $total ) return $wpdb->get_var($queryObj); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + // Catch count/total + return if requested + if ( $count || $total ) return $wpdb->get_var( $queryObj ); - } catch (Exception $e){ + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - #} General SQL Err - $this->catchSQLError($e); + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + } - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // only columns? - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - // only coumns return. - $resArr = array(); - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - if (isset($resDataLine->$colDBKey)) $resArr[$colStr] = $resDataLine->$colDBKey; + // only columns? + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - } + // only coumns return. + $resArr = array(); + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { + if (isset( $resDataLine->$colDBKey )) $resArr[ $colStr ] = $resDataLine->$colDBKey; - } else { + } + } else { - // tidy - $resArr = $this->tidy_transaction($resDataLine,$withCustomFields); + // tidy + $resArr = $this->tidy_transaction( $resDataLine, $withCustomFields ); - } + } - if ($withLineItems){ + if ( $withLineItems ) { - // add all line item lines - $resArr['lineitems'] = $this->DAL()->lineitems->getLineitems(array('associatedObjType'=>ZBS_TYPE_TRANSACTION,'associatedObjID'=>$resDataLine->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LINEITEM))); - - } + // add all line item lines + $resArr['lineitems'] = $this->DAL()->lineitems->getLineitems( + array( + 'associatedObjType' => ZBS_TYPE_TRANSACTION, + 'associatedObjID' => $resDataLine->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LINEITEM ), + ) + ); - if ($withTags){ + } - // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_TRANSACTION,'objid'=>$resDataLine->ID)); + if ( $withTags ) { - } + // add all tags lines + $resArr['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_TRANSACTION, + 'objid' => $resDataLine->ID, + ) + ); - if ($withAssigned){ - - /* This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) - - // add all assigned contacts/companies - $res['contacts'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); - - .. but we use 1:1, at least now: */ - - // add all assigned contacts/companies - $resArr['contact'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - - $resArr['company'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); - - - } + } - if ( $external_source_uid ) { - $resArr['external_source_uid'] = $this->tidy_external_sources( $resDataLine ); - } + if ( $withAssigned ) { + + /* + This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + + // add all assigned contacts/companies + $res['contacts'] = $this->DAL()->contacts->getContacts(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + + $res['companies'] = $this->DAL()->companies->getCompanies(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + + .. but we use 1:1, at least now: */ + + // add all assigned contacts/companies + $resArr['contact'] = $this->DAL()->contacts->getContacts( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo' => $resDataLine->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); - $res[] = $resArr; + $resArr['company'] = $this->DAL()->companies->getCompanies( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo' => $resDataLine->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); - } - } + } - return $res; - } + if ( $external_source_uid ) { + $resArr['external_source_uid'] = $this->tidy_external_sources( $resDataLine ); + } + $res[] = $resArr; - /** - * Returns a count of transactions (owned) - * .. inc by status - * - * @return int count - */ - public function getTransactionCount($args=array()){ + } + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + return $res; + } - // Search/Filtering (leave as false to ignore) - 'withStatus' => false, // will be str if used + /** + * Returns a count of transactions (owned) + * .. inc by status + * + * @return int count + */ + public function getTransactionCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'withStatus' => false, // will be str if used // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - $whereArr = array(); - - if ($withStatus !== false && !empty($withStatus)) $whereArr['status'] = array('zbst_status','=','%s',$withStatus); - - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_TRANSACTION, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - } - - - /** - * adds or updates a transaction object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateTransaction($args=array()){ - - global $ZBSCRM_t,$wpdb,$zbs; - - #} Retrieve any cf - $customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_TRANSACTION)); - // not req. $addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1, - 'owner' => -1, - - // fields (directly) - 'data' => array( - - - 'status' => '', - 'type' => '', - 'ref' => '', - 'origin' => '', - 'parent' => '', - 'hash' => '', - 'title' => '', - 'desc' => '', - 'date' => '', - 'customer_ip' => '', - 'currency' => '', - 'net' => '', - 'fee' => '', - 'discount' => '', - 'shipping' => '', - 'shipping_taxes' => '', - 'shipping_tax' => '', - 'taxes' => '', - 'tax' => '', - 'total' => '', - 'date_paid' => null, - 'date_completed' => null, - - // lineitems: - 'lineitems' => false, - // will be an array of lineitem lines (as per matching lineitem database model) - // note: if no change desired, pass "false" - // if removal of all/change, pass empty array - - // Note Custom fields may be passed here, but will not have defaults so check isset() - - // obj links: - 'contacts' => false, // array of id's - 'companies' => false, // array of id's - 'invoice_id' => false, // ID if assigned to an invoice - - // tags - 'tags' => -1, // pass an array of tag ids or tag strings - 'tag_mode' => 'replace', // replace|append|remove - - 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) - - // allow this to be set for MS sync etc. - 'created' => -1, - 'lastupdated' => '', - - ), - - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) - // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + 'ignoreowner' => true, // this'll let you not-check the owner of obj + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData )) $newData = array(); + foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + $whereArr = array(); - // this function as DAL1 func did. - 'extraMeta' => -1, - 'automatorPassthrough' => -1, + if ($withStatus !== false && ! empty( $withStatus )) $whereArr['status'] = array( 'zbst_status', '=', '%s', $withStatus ); - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newTransaction (because is migrating, not creating new :) this was -1 before + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_TRANSACTION, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + } - 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) - 'do_not_mark_invoices' => false // by default all trans associated with an INV will fire a check "should this inv be marked paid" on add/update of trans. If this is true, check will not run + /** + * adds or updates a transaction object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateTransaction( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} Retrieve any cf + $customFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_TRANSACTION ) ); + // not req. $addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'owner' => -1, + + // fields (directly) + 'data' => array( + + 'status' => '', + 'type' => '', + 'ref' => '', + 'origin' => '', + 'parent' => '', + 'hash' => '', + 'title' => '', + 'desc' => '', + 'date' => '', + 'customer_ip' => '', + 'currency' => '', + 'net' => '', + 'fee' => '', + 'discount' => '', + 'shipping' => '', + 'shipping_taxes' => '', + 'shipping_tax' => '', + 'taxes' => '', + 'tax' => '', + 'total' => '', + 'date_paid' => null, + 'date_completed' => null, + + // lineitems: + 'lineitems' => false, + // will be an array of lineitem lines (as per matching lineitem database model) + // note: if no change desired, pass "false" + // if removal of all/change, pass empty array + + // Note Custom fields may be passed here, but will not have defaults so check isset() + + // obj links: + 'contacts' => false, // array of id's + 'companies' => false, // array of id's + 'invoice_id' => false, // ID if assigned to an invoice + + // tags + 'tags' => -1, // pass an array of tag ids or tag strings + 'tag_mode' => 'replace', // replace|append|remove + + 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) + + // allow this to be set for MS sync etc. + 'created' => -1, + 'lastupdated' => '', + + ), + + 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + // ^^ will look like: array(array('key'=>x,'val'=>y,'type'=>'%s')) + + // this function as DAL1 func did. + 'extraMeta' => -1, + 'automatorPassthrough' => -1, + + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newTransaction (because is migrating, not creating new :) this was -1 before + + 'do_not_update_blanks' => false, // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + 'do_not_mark_invoices' => false, // by default all trans associated with an INV will fire a check "should this inv be marked paid" on add/update of trans. If this is true, check will not run + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData )) $newData = array(); + foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - // Needs this to grab custom fields (if passed) too :) - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + if (is_array( $customFields )) foreach ( $customFields as $cK => $cF ) { // only for data, limited fields below - if (is_array($data)) { + if ( is_array( $data ) ) { - if (isset($args['data'][$cK])) $data[$cK] = $args['data'][$cK]; + if (isset( $args['data'][ $cK ] )) $data[ $cK ] = $args['data'][ $cK ]; } - - } + } // this takes limited fields + checks through for custom fields present // (either as key zbst_source or source, for example) // then switches them into the $data array, for separate update // where this'll fall over is if NO normal contact data is sent to update, just custom fields - if (is_array($limitedFields) && is_array($customFields)){ + if ( is_array( $limitedFields ) && is_array( $customFields ) ) { - //$customFieldKeys = array_keys($customFields); + // $customFieldKeys = array_keys($customFields); $newLimitedFields = array(); // cycle through - foreach ($limitedFields as $field){ + foreach ( $limitedFields as $field ) { - // some weird case where getting empties, so added check - if (isset($field['key']) && !empty($field['key'])){ + // some weird case where getting empties, so added check + if ( isset( $field['key'] ) && ! empty( $field['key'] ) ) { $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase if ( str_starts_with( $field['key'], 'zbst_' ) ) { $dePrefixed = substr( $field['key'], strlen( 'zbst_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - if (isset($customFields[$field['key']])){ - - // is custom, move to data - $data[$field['key']] = $field['val']; - - } else if (!empty($dePrefixed) && isset($customFields[$dePrefixed])){ + if ( isset( $customFields[ $field['key'] ] ) ) { - // is custom, move to data - $data[$dePrefixed] = $field['val']; + // is custom, move to data + $data[ $field['key'] ] = $field['val']; - } else { + } elseif ( ! empty( $dePrefixed ) && isset( $customFields[ $dePrefixed ] ) ) { - // add it to limitedFields (it's not dealt with post-update) - $newLimitedFields[] = $field; - } + // is custom, move to data + $data[ $dePrefixed ] = $field['val']; - } + } else { - } + // add it to limitedFields (it's not dealt with post-update) + $newLimitedFields[] = $field; + } + } + } // move this back in $limitedFields = $newLimitedFields; - unset($newLimitedFields); + unset( $newLimitedFields ); - } + } + + #} =========== / LOAD ARGS ============ - #} =========== / LOAD ARGS ============ + #} ========== CHECK FIELDS ============ + + $id = (int) $id; - #} ========== CHECK FIELDS ============ - - $id = (int)$id; - // here we check that the potential owner CAN even own - if ($owner > 0 && !user_can($owner,'admin_zerobs_usr')) $owner = -1; + if ($owner > 0 && ! user_can( $owner, 'admin_zerobs_usr' )) $owner = -1; // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } - + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); } - if (is_array($limitedFields)){ + if ( is_array( $limitedFields ) ) { // LIMITED UPDATE (only a few fields.) - if (!is_array($limitedFields) || count ($limitedFields) <= 0) return false; + if ( ! is_array( $limitedFields ) || count( $limitedFields ) <= 0) return false; // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; + if (empty( $id ) || $id <= 0) return false; - } else { + } else { // NORMAL, FULL UPDATE - } - + } #} If no status, and default is specified in settings, add that in :) // for now, I copied this from addUpdateTransaction: 'Unknown'; - if (is_null($data['status']) || !isset($data['status']) || empty($data['status'])){ + if ( $data['status'] === null || ! isset( $data['status'] ) || empty( $data['status'] ) ) { - // Default status for obj? -> this one gets for contacts -> - $data['status'] = __('Unknown','zero-bs-crm'); //zeroBSCRM_getSetting('defaultstatus'); + // Default status for obj? -> this one gets for contacts -> + $data['status'] = __( 'Unknown', 'zero-bs-crm' ); // zeroBSCRM_getSetting('defaultstatus'); - } - - - #} ========= / CHECK FIELDS =========== + } + #} ========= / CHECK FIELDS =========== - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== // this only functions if externalsource is set (e.g. api/form, etc.) - if (isset($data['externalSources']) && is_array($data['externalSources']) && count($data['externalSources']) > 0) { - if (zeroBSCRM_getSetting('fieldoverride') == "1"){ + if ( isset( $data['externalSources'] ) && is_array( $data['externalSources'] ) && count( $data['externalSources'] ) > 0 ) { + if ( zeroBSCRM_getSetting( 'fieldoverride' ) == '1' ) { - $do_not_update_blanks = true; + $do_not_update_blanks = true; - } - - } + } + } // either ext source + setting, or set by the func call - if ($do_not_update_blanks){ - - // this setting says 'don't override filled-out data with blanks' - // so here we check through any passed blanks + convert to limitedFields - // only matters if $id is set (there is somt to update not add - if (isset($id) && !empty($id) && $id > 0){ + if ( $do_not_update_blanks ) { - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_transaction($data); - //unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue - //unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) + // this setting says 'don't override filled-out data with blanks' + // so here we check through any passed blanks + convert to limitedFields + // only matters if $id is set (there is somt to update not add + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - $origData = $data; //$data = array(); - $limitedData = array(); // array(array('key'=>'zbst_x','val'=>y,'type'=>'%s')) + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_transaction( $data ); + // unset($dbData['id']); // this is unset because we use $id, and is update, so not req. legacy issue + // unset($dbData['created']); // this is unset because this uses an obj which has been 'updated' against original details, where created is output in the WRONG format :) - // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) - // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates - foreach ($dbData as $k => $v){ + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbst_x','val'=>y,'type'=>'%s')) - $intV = (int)$v; + // cycle through + translate into limitedFields (removing any blanks, or arrays (e.g. externalSources)) + // we also have to remake a 'faux' data (removing blanks for tags etc.) for the post-update updates + foreach ( $dbData as $k => $v ) { - // only add if valuenot empty - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ + $intV = (int) $v; - // add to update arr - $limitedData[] = array( - 'key' => 'zbst_'.$k, // we have to add zbst_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbst_'.$k) - ); - - // add to remade $data for post-update updates - $data[$k] = $v; - - } - - } + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { - // copy over - $limitedFields = $limitedData; + // add to update arr + $limitedData[] = array( + 'key' => 'zbst_' . $k, // we have to add zbst_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbst_' . $k ), + ); - } // / if ID + // add to remade $data for post-update updates + $data[ $k ] = $v; - } // / if do_not_update_blanks + } + } - #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== + // copy over + $limitedFields = $limitedData; + } // / if ID - #} ========= BUILD DATA =========== + } // / if do_not_update_blanks - $update = false; $dataArr = array(); $typeArr = array(); + #} ========= / OVERRIDE SETTING (Deny blank overrides) =========== - if (is_array($limitedFields)){ + #} ========= BUILD DATA =========== - // LIMITED FIELDS - $update = true; + $update = false; + $dataArr = array(); + $typeArr = array(); - // cycle through - foreach ($limitedFields as $field){ + if ( is_array( $limitedFields ) ) { - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } + // LIMITED FIELDS + $update = true; - } + // cycle through + foreach ( $limitedFields as $field ) { - // add update time - if (!isset($dataArr['zbst_lastupdated'])){ $dataArr['zbst_lastupdated'] = time(); $typeArr[] = '%d'; } + // some weird case where getting empties, so added check + if ( ! empty( $field['key'] ) ) { + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } + } - } else { + // add update time + if ( ! isset( $dataArr['zbst_lastupdated'] ) ) { + $dataArr['zbst_lastupdated'] = time(); + $typeArr[] = '%d'; } + } else { - // FULL UPDATE/INSERT + // FULL UPDATE/INSERT - // contacts - avoid dupes - if (isset($data['contacts']) && is_array($data['contacts'])){ + // contacts - avoid dupes + if ( isset( $data['contacts'] ) && is_array( $data['contacts'] ) ) { - $coArr = array(); - foreach ($data['contacts'] as $c){ - $cI = (int)$c; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; - } + $coArr = array(); + foreach ( $data['contacts'] as $c ) { + $cI = (int) $c; + if ($cI > 0 && ! in_array( $cI, $coArr )) $coArr[] = $cI; + } - // reset the main - if (count($coArr) > 0) - $data['contacts'] = $coArr; - else - $data['contacts'] = 'unset'; - unset($coArr); + // reset the main + if (count( $coArr ) > 0) + $data['contacts'] = $coArr; + else $data['contacts'] = 'unset'; + unset( $coArr ); - } + } - // companies - avoid dupes - if (isset($data['companies']) && is_array($data['companies'])){ + // companies - avoid dupes + if ( isset( $data['companies'] ) && is_array( $data['companies'] ) ) { - $coArr = array(); - foreach ($data['companies'] as $c){ - $cI = (int)$c; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; - } + $coArr = array(); + foreach ( $data['companies'] as $c ) { + $cI = (int) $c; + if ($cI > 0 && ! in_array( $cI, $coArr )) $coArr[] = $cI; + } - // reset the main - if (count($coArr) > 0) - $data['companies'] = $coArr; - else - $data['companies'] = 'unset'; - unset($coArr); + // reset the main + if (count( $coArr ) > 0) + $data['companies'] = $coArr; + else $data['companies'] = 'unset'; + unset( $coArr ); - } + } - // UPDATE - $dataArr = array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, - - - 'zbst_status' => $data['status'], - 'zbst_type' => $data['type'], - 'zbst_ref' => $data['ref'], - 'zbst_origin' => $data['origin'], - 'zbst_parent' => $data['parent'], - 'zbst_hash' => $data['hash'], - 'zbst_title' => $data['title'], - 'zbst_desc' => $data['desc'], - 'zbst_date' => $data['date'], - 'zbst_customer_ip' => $data['customer_ip'], - 'zbst_currency' => $data['currency'], - 'zbst_net' => $data['net'], - 'zbst_fee' => $data['fee'], - 'zbst_discount' => $data['discount'], - 'zbst_shipping' => $data['shipping'], - 'zbst_shipping_taxes' => $data['shipping_taxes'], - 'zbst_shipping_tax' => $data['shipping_tax'], - 'zbst_taxes' => $data['taxes'], - 'zbst_tax' => $data['tax'], - 'zbst_total' => $data['total'], - 'zbst_date_paid' => $data['date_paid'], - 'zbst_date_completed' => $data['date_completed'], - 'zbst_lastupdated' => time(), + // UPDATE + $dataArr = array( + + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, + + 'zbst_status' => $data['status'], + 'zbst_type' => $data['type'], + 'zbst_ref' => $data['ref'], + 'zbst_origin' => $data['origin'], + 'zbst_parent' => $data['parent'], + 'zbst_hash' => $data['hash'], + 'zbst_title' => $data['title'], + 'zbst_desc' => $data['desc'], + 'zbst_date' => $data['date'], + 'zbst_customer_ip' => $data['customer_ip'], + 'zbst_currency' => $data['currency'], + 'zbst_net' => $data['net'], + 'zbst_fee' => $data['fee'], + 'zbst_discount' => $data['discount'], + 'zbst_shipping' => $data['shipping'], + 'zbst_shipping_taxes' => $data['shipping_taxes'], + 'zbst_shipping_tax' => $data['shipping_tax'], + 'zbst_taxes' => $data['taxes'], + 'zbst_tax' => $data['tax'], + 'zbst_total' => $data['total'], + 'zbst_date_paid' => $data['date_paid'], + 'zbst_date_completed' => $data['date_completed'], + 'zbst_lastupdated' => time(), - ); + ); - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner - - - '%s', - '%s', - '%s', - '%s', - '%d', - '%s', - '%s', - '%s', - '%d', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%d', - '%d', - '%d', + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner + + '%s', + '%s', + '%s', + '%s', + '%d', + '%s', + '%s', + '%s', + '%d', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%d', + '%d', + '%d', - ); + ); - if (!empty($id) && $id > 0){ + if ( ! empty( $id ) && $id > 0 ) { // is update $update = true; - } else { + } else { // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $typeArr[] = '%d'; - $dataArr['zbs_owner'] = $owner; $typeArr[] = '%d'; - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbst_created'] = $data['created'];$typeArr[] = '%d'; + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; + $dataArr['zbs_owner'] = $owner; + $typeArr[] = '%d'; + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbst_created'] = $data['created']; + $typeArr[] = '%d'; } else { - $dataArr['zbst_created'] = time(); $typeArr[] = '%d'; + $dataArr['zbst_created'] = time(); + $typeArr[] = '%d'; } // if no transaction date is passed on creation, use time() // allow for 0 value (valid epoch time) - if ( empty($dataArr['zbst_date']) && $dataArr['zbst_date'] !== 0 ) { + if ( empty( $dataArr['zbst_date'] ) && $dataArr['zbst_date'] !== 0 ) { $dataArr['zbst_date'] = time(); } + } + } - } - - } - - - #} ========= / BUILD DATA =========== + #} ========= / BUILD DATA =========== - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== - // if we're passing limitedFields we skip these, for now + // if we're passing limitedFields we skip these, for now // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ + if ( ! is_array( $limitedFields ) ) { - // verify uniques - if (!$this->verifyUniqueValues($data,$id)) return false; // / fails unique field verify + // verify uniques + if ( ! $this->verifyUniqueValues( $data, $id )) return false; // / fails unique field verify - // verify not_empty - if (!$this->verifyNonEmptyValues($data)) return false; // / fails empty field verify + // verify not_empty + if ( ! $this->verifyNonEmptyValues( $data )) return false; // / fails empty field verify - } + } // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks($dataArr); - - #} ========= / CHECK force_uniques & not_empty ================ - #} ============================================================ + $dataArr = $this->wpdbChecks( $dataArr ); - #} Check if ID present - if ($update){ + #} ========= / CHECK force_uniques & not_empty ================ + #} ============================================================ + #} Check if ID present + if ( $update ) { #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - $originalStatus = $this->getTransactionStatus($id); + $originalStatus = $this->getTransactionStatus( $id ); // log any change of status - if (isset($dataArr['zbst_status']) && !empty($dataArr['zbst_status']) && !empty($originalStatus) && $dataArr['zbst_status'] != $originalStatus){ + if ( isset( $dataArr['zbst_status'] ) && ! empty( $dataArr['zbst_status'] ) && ! empty( $originalStatus ) && $dataArr['zbst_status'] != $originalStatus ) { - // status change - $statusChange = array( - 'from' => $originalStatus, - 'to' => $dataArr['zbst_status'] - ); - } - + // status change + $statusChange = array( + 'from' => $originalStatus, + 'to' => $dataArr['zbst_status'], + ); + } #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['transactions'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ - - - // if passing limitedFields instead of data, we ignore the following - // this doesn't work, because data is in args default as arr - //if (isset($data) && is_array($data)){ - // so... - if (!isset($limitedFields) || !is_array($limitedFields) || $limitedFields == -1){ - - - // Line Items ==== - - // line item work - if (isset($data['lineitems']) && is_array($data['lineitems'])){ - - // if array passed, update, even if removing - if (count($data['lineitems']) > 0){ - - // passed, for now this is BRUTAL and just clears old ones + readds - // once live, discuss how to refactor to be less brutal. - - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$id,'objType'=>ZBS_TYPE_TRANSACTION)); - - // addupdate each - foreach ($data['lineitems'] as $lineitem) { - - // slight rejig of passed so works cleanly with data array style - $lineItemID = false; if (isset($lineitem['ID'])) $lineItemID = $lineitem['ID']; - $this->DAL()->lineitems->addUpdateLineitem(array( - 'id'=>$lineItemID, - 'linkedObjType' => ZBS_TYPE_TRANSACTION, - 'linkedObjID' => $id, - 'data'=>$lineitem - )); + if ( $wpdb->update( + $ZBSCRM_t['transactions'], + $dataArr, + array( // where + 'ID' => $id, + ), + $typeArr, + array( // where data types + '%d', + ) + ) !== false ) { + + // if passing limitedFields instead of data, we ignore the following + // this doesn't work, because data is in args default as arr + // if (isset($data) && is_array($data)){ + // so... + if ( ! isset( $limitedFields ) || ! is_array( $limitedFields ) || $limitedFields == -1 ) { + + // Line Items ==== + + // line item work + if ( isset( $data['lineitems'] ) && is_array( $data['lineitems'] ) ) { + + // if array passed, update, even if removing + if ( count( $data['lineitems'] ) > 0 ) { + + // passed, for now this is BRUTAL and just clears old ones + readds + // once live, discuss how to refactor to be less brutal. + + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $id, + 'objType' => ZBS_TYPE_TRANSACTION, + ) + ); - } + // addupdate each + foreach ( $data['lineitems'] as $lineitem ) { - } else { + // slight rejig of passed so works cleanly with data array style + $lineItemID = false; + if (isset( $lineitem['ID'] )) $lineItemID = $lineitem['ID']; + $this->DAL()->lineitems->addUpdateLineitem( + array( + 'id' => $lineItemID, + 'linkedObjType' => ZBS_TYPE_TRANSACTION, + 'linkedObjID' => $id, + 'data' => $lineitem, + ) + ); - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$id,'objType'=>ZBS_TYPE_TRANSACTION)); + } + } else { - } + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $id, + 'objType' => ZBS_TYPE_TRANSACTION, + ) + ); + } + } - } + // / Line Items ==== - // / Line Items ==== + // OBJ LINKS - to contacts/companies + $this->addUpdateObjectLinks( $id, $data['contacts'], ZBS_TYPE_CONTACT ); + $this->addUpdateObjectLinks( $id, $data['companies'], ZBS_TYPE_COMPANY ); - // OBJ LINKS - to contacts/companies - $this->addUpdateObjectLinks($id,$data['contacts'],ZBS_TYPE_CONTACT); - $this->addUpdateObjectLinks($id,$data['companies'],ZBS_TYPE_COMPANY); + // IA also gets 'againstid' historically, but we'll pass as 'against id's' + $againstIDs = array( + 'contacts' => $data['contacts'], + 'companies' => $data['companies'], + ); - // IA also gets 'againstid' historically, but we'll pass as 'against id's' - $againstIDs = array('contacts'=>$data['contacts'],'companies'=>$data['companies']); + // OBJ Links - to invoices + $this->addUpdateObjectLinks( $id, array( $data['invoice_id'] ), ZBS_TYPE_INVOICE ); - // OBJ Links - to invoices - $this->addUpdateObjectLinks($id,array($data['invoice_id']),ZBS_TYPE_INVOICE); + // if not-empty inv id, check if needs to be mark paid! + if ( ! $do_not_mark_invoices && ! empty( $data['invoice_id'] ) && $data['invoice_id'] > 0 ) { - // if not-empty inv id, check if needs to be mark paid! - if (!$do_not_mark_invoices && !empty($data['invoice_id']) && $data['invoice_id'] > 0){ + // function to check ammount due and mark invoice as paid if amount due <= 0. + zeroBSCRM_check_amount_due_mark_paid( $data['invoice_id'] ); - //function to check ammount due and mark invoice as paid if amount due <= 0. - zeroBSCRM_check_amount_due_mark_paid($data['invoice_id']); - - } - + } - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { - $this->addUpdateTransactionTags( - array( - 'id' => $id, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + $this->addUpdateTransactionTags( + array( + 'id' => $id, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); - } + } - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( array( - 'obj_id' => $id, - 'obj_type_id' => ZBS_TYPE_TRANSACTION, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), + 'obj_id' => $id, + 'obj_type_id' => ZBS_TYPE_TRANSACTION, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), ) ); // for IA below - // Custom fields? + // Custom fields? - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + #} Cycle through + add/update if set + if (is_array( $customFields )) foreach ( $customFields as $cK => $cF ) { - // any? - if (isset($data[$cK])){ + // any? + if ( isset( $data[ $cK ] ) ) { - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_TRANSACTION, - 'objid' => $id, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); - - } - - } - - // / Custom Fields - - } else { - - // limited fields - // here we set what will not have been passed as blanks, for the IA to use below. - $againstIDs = false; - $approvedExternalSource = ''; - - } - - // Any extra meta keyval pairs - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_TRANSACTION, + 'objid' => $id, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); - $confirmedExtraMeta = array(); + } + } - foreach ($extraMeta as $k => $v){ + // / Custom Fields - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + } else { - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_TRANSACTION,$id,'extra_'.$cleanKey,$v); + // limited fields + // here we set what will not have been passed as blanks, for the IA to use below. + $againstIDs = false; + $approvedExternalSource = ''; - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + } - } + // Any extra meta keyval pairs + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + $confirmedExtraMeta = array(); + foreach ( $extraMeta as $k => $v ) { - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - // catch dirty flag (update of status) (note, after update_post_meta - as separate) - //if (isset($_POST['zbst_status_dirtyflag']) && $_POST['zbst_status_dirtyflag'] == "1"){ - // actually here, it's set above - if (isset($statusChange) && is_array($statusChange)){ + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_TRANSACTION, $id, 'extra_' . $cleanKey, $v ); - // status has changed + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - // IA - zeroBSCRM_FireInternalAutomator('transaction.status.update',array( - 'id' => $id, - 'againstids' => $againstIDs, - 'data' => $data, - 'from' => $statusChange['from'], - 'to' => $statusChange['to'] - )); + } + } - } + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // UPDATING CONTACT + if ( ! $silentInsert ) { + + // catch dirty flag (update of status) (note, after update_post_meta - as separate) + // if (isset($_POST['zbst_status_dirtyflag']) && $_POST['zbst_status_dirtyflag'] == "1"){ + // actually here, it's set above + if ( isset( $statusChange ) && is_array( $statusChange ) ) { + + // status has changed + + // IA + zeroBSCRM_FireInternalAutomator( + 'transaction.status.update', + array( + 'id' => $id, + 'againstids' => $againstIDs, + 'data' => $data, + 'from' => $statusChange['from'], + 'to' => $statusChange['to'], + ) + ); + } - // IA General transaction update (2.87+) - zeroBSCRM_FireInternalAutomator('transaction.update',array( - 'id' => $id, - 'data' => $data, - 'againstids' => $againstIDs, - 'extsource' => $approvedExternalSource, - 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta' => $confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); + // IA General transaction update (2.87+) + zeroBSCRM_FireInternalAutomator( + 'transaction.update', + array( + 'id' => $id, + 'data' => $data, + 'againstids' => $againstIDs, + 'extsource' => $approvedExternalSource, + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); - $data['id'] = $id; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $this->events_manager->transaction()->updated( $data ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - + $data['id'] = $id; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $this->events_manager->transaction()->updated( $data ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } - - // Successfully updated - Return id - return $id; + } - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); + // Successfully updated - Return id + return $id; - // FAILED update - return false; + } else { - } + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['transactions'], - $dataArr, - $typeArr ) > 0){ + // FAILED update + return false; - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - - // Line Items ==== + } + } else { - // line item work - if (isset($data['lineitems']) && is_array($data['lineitems'])){ + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['transactions'], + $dataArr, + $typeArr + ) > 0 ) { - // if array passed, update, even if removing - if (count($data['lineitems']) > 0){ + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - // passed, for now this is BRUTAL and just clears old ones + readds - // once live, discuss how to refactor to be less brutal. + // Line Items ==== - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$newID,'objType'=>ZBS_TYPE_TRANSACTION)); + // line item work + if ( isset( $data['lineitems'] ) && is_array( $data['lineitems'] ) ) { - // addupdate each - foreach ($data['lineitems'] as $lineitem) { + // if array passed, update, even if removing + if ( count( $data['lineitems'] ) > 0 ) { - // slight rejig of passed so works cleanly with data array style - $lineItemID = false; if (isset($lineitem['ID'])) $lineItemID = $lineitem['ID']; - $this->DAL()->lineitems->addUpdateLineitem(array( - 'id'=>$lineItemID, - 'linkedObjType' => ZBS_TYPE_TRANSACTION, - 'linkedObjID' => $newID, - 'data'=>$lineitem - )); + // passed, for now this is BRUTAL and just clears old ones + readds + // once live, discuss how to refactor to be less brutal. - } + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $newID, + 'objType' => ZBS_TYPE_TRANSACTION, + ) + ); - } else { + // addupdate each + foreach ( $data['lineitems'] as $lineitem ) { - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$newID,'objType'=>ZBS_TYPE_TRANSACTION)); + // slight rejig of passed so works cleanly with data array style + $lineItemID = false; + if (isset( $lineitem['ID'] )) $lineItemID = $lineitem['ID']; + $this->DAL()->lineitems->addUpdateLineitem( + array( + 'id' => $lineItemID, + 'linkedObjType' => ZBS_TYPE_TRANSACTION, + 'linkedObjID' => $newID, + 'data' => $lineitem, + ) + ); - } + } + } else { + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $newID, + 'objType' => ZBS_TYPE_TRANSACTION, + ) + ); - } + } + } - // / Line Items ==== + // / Line Items ==== - // OBJ LINKS - to contacts/companies - $this->addUpdateObjectLinks($newID,$data['contacts'],ZBS_TYPE_CONTACT); - $this->addUpdateObjectLinks($newID,$data['companies'],ZBS_TYPE_COMPANY); - // IA also gets 'againstid' historically, but we'll pass as 'against id's' - $againstIDs = array('contacts'=>$data['contacts'],'companies'=>$data['companies']); + // OBJ LINKS - to contacts/companies + $this->addUpdateObjectLinks( $newID, $data['contacts'], ZBS_TYPE_CONTACT ); + $this->addUpdateObjectLinks( $newID, $data['companies'], ZBS_TYPE_COMPANY ); + // IA also gets 'againstid' historically, but we'll pass as 'against id's' + $againstIDs = array( + 'contacts' => $data['contacts'], + 'companies' => $data['companies'], + ); - // OBJ Links - to invoices - $this->addUpdateObjectLinks($newID,array($data['invoice_id']),ZBS_TYPE_INVOICE); + // OBJ Links - to invoices + $this->addUpdateObjectLinks( $newID, array( $data['invoice_id'] ), ZBS_TYPE_INVOICE ); - // if not-empty inv id, check if needs to be mark paid! - if (!$do_not_mark_invoices && !empty($data['invoice_id']) && $data['invoice_id'] > 0){ + // if not-empty inv id, check if needs to be mark paid! + if ( ! $do_not_mark_invoices && ! empty( $data['invoice_id'] ) && $data['invoice_id'] > 0 ) { - //function to check ammount due and mark invoice as paid if amount due <= 0. - zeroBSCRM_check_amount_due_mark_paid($data['invoice_id']); + // function to check ammount due and mark invoice as paid if amount due <= 0. + zeroBSCRM_check_amount_due_mark_paid( $data['invoice_id'] ); - } + } // tags - if (isset($data['tags']) && is_array($data['tags'])) { + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { - $this->addUpdateTransactionTags( + $this->addUpdateTransactionTags( array( - 'id' => $newID, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] + 'id' => $newID, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], ) - ); + ); - } + } // externalSources $approvedExternalSource = $this->DAL()->addUpdateExternalSources( array( - 'obj_id' => $newID, - 'obj_type_id' => ZBS_TYPE_TRANSACTION, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), + 'obj_id' => $newID, + 'obj_type_id' => ZBS_TYPE_TRANSACTION, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), ) ); // for IA below - // Custom fields? - - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + // Custom fields? - // any? - if (isset($data[$cK])){ + #} Cycle through + add/update if set + if (is_array( $customFields )) foreach ( $customFields as $cK => $cF ) { - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_TRANSACTION, - 'objid' => $newID, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + // any? + if ( isset( $data[ $cK ] ) ) { - } - - } + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_TRANSACTION, + 'objid' => $newID, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); - // / Custom Fields + } + } - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // / Custom Fields - $confirmedExtraMeta = array(); + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - foreach ($extraMeta as $k => $v){ + $confirmedExtraMeta = array(); - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + foreach ( $extraMeta as $k => $v ) { - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_TRANSACTION,$newID,'extra_'.$cleanKey,$v); + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_TRANSACTION, $newID, 'extra_' . $cleanKey, $v ); - } + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - } + } + } + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // NEW CONTACT + if ( ! $silentInsert ) { + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'transaction.new', + array( + 'id' => $newID, + 'data' => $data, + 'againstids' => $againstIDs, + 'extsource' => $approvedExternalSource, + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'extraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); + $data['id'] = $newID; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $this->events_manager->transaction()->created( $data ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + } - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT - if (!$silentInsert){ - - #} Add to automator - zeroBSCRM_FireInternalAutomator('transaction.new',array( - 'id'=>$newID, - 'data'=>$data, - 'againstids'=>$againstIDs, - 'extsource'=>$approvedExternalSource, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'extraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); - $data['id'] = $newID; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $this->events_manager->transaction()->created( $data ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } - - return $newID; + return $newID; - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); + } else { - #} Failed to Insert - return false; + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); - } + #} Failed to Insert + return false; - } + } + } - return false; + return false; + } - } + /** + * adds or updates a transaction's tags + * ... this is really just a wrapper for addUpdateObjectTags + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateTransactionTags( $args = array() ) { + + global $ZBSCRM_t, $wpdb; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + + // generic pass-through (array of tag strings or tag IDs): + 'tag_input' => -1, + + // or either specific: + 'tagIDs' => -1, + 'tags' => -1, + + 'mode' => 'append', + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData )) $newData = array(); + foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - /** - * adds or updates a transaction's tags - * ... this is really just a wrapper for addUpdateObjectTags - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateTransactionTags($args=array()){ + #} ========== CHECK FIELDS ============ - global $ZBSCRM_t,$wpdb; + // check id + $id = (int) $id; + if (empty( $id ) || $id <= 0) return false; + + #} ========= / CHECK FIELDS =========== + + return $this->DAL()->addUpdateObjectTags( + array( + 'objtype' => ZBS_TYPE_TRANSACTION, + 'objid' => $id, + 'tag_input' => $tag_input, + 'tags' => $tags, + 'tagIDs' => $tagIDs, + 'mode' => $mode, + ) + ); + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + /** + * updates status for a transaction (no blanks allowed) + * + * @param int id transaction ID + * @param string transaction Status + * + * @return bool + */ + public function setTransactionStatus( $id = -1, $status = -1 ) { - 'id' => -1, - - // generic pass-through (array of tag strings or tag IDs): - 'tag_input' => -1, + global $zbs; - // or either specific: - 'tagIDs' => -1, - 'tags' => -1, - - 'mode' => 'append' + $id = (int) $id; - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + if ( $id > 0 && ! empty( $status ) && $status !== -1 ) { - #} ========== CHECK FIELDS ============ + return $this->addUpdateTransaction( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbst_status', + 'val' => $status, + 'type' => '%s', + ), + ), + ) + ); - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; - - #} ========= / CHECK FIELDS =========== - - return $this->DAL()->addUpdateObjectTags( - array( - 'objtype' => ZBS_TYPE_TRANSACTION, - 'objid' => $id, - 'tag_input' => $tag_input, - 'tags' => $tags, - 'tagIDs' => $tagIDs, - 'mode' => $mode - ) - ); + } - } + return false; + } - /** - * updates status for a transaction (no blanks allowed) - * - * @param int id transaction ID - * @param string transaction Status - * - * @return bool - */ - public function setTransactionStatus($id=-1,$status=-1){ + /** + * deletes a transaction object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteTransaction( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'saveOrphans' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData )) $newData = array(); + foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - global $zbs; + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - $id = (int)$id; + // delete orphans? + if ( $saveOrphans === false ) { - if ($id > 0 && !empty($status) && $status !== -1){ + // delete any tag links + $this->DAL()->deleteTagObjLinks( + array( - return $this->addUpdateTransaction(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbst_status','val' => $status,'type' => '%s') - ))); + 'objtype' => ZBS_TYPE_TRANSACTION, + 'objid' => $id, - } + ) + ); - return false; - - } + // delete any external source information + $this->DAL()->delete_external_sources( + array( + 'obj_type' => ZBS_TYPE_TRANSACTION, + 'obj_id' => $id, + 'obj_source' => 'all', + ) + ); - /** - * deletes a transaction object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteTransaction($args=array()){ + } - global $ZBSCRM_t,$wpdb,$zbs; + $del = zeroBSCRM_db2_deleteGeneric( $id, 'transactions' ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'transaction.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); - 'id' => -1, - 'saveOrphans' => false + $this->events_manager->transaction()->deleted( $id ); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + return $del; - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ + } - // delete any tag links - $this->DAL()->deleteTagObjLinks(array( + return false; + } - 'objtype' => ZBS_TYPE_TRANSACTION, - 'objid' => $id, + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array transaction (clean obj) + */ + private function tidy_transaction( $obj = false, $withCustomFields = false ) { - )); + $res = false; - // delete any external source information - $this->DAL()->delete_external_sources( array( + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = $obj->zbs_owner; + + $res['status'] = $this->stripSlashes( $obj->zbst_status ); + $res['type'] = $this->stripSlashes( $obj->zbst_type ); + + // status categorisation (basically did it succeed?) + // this is dictated by Transaction Status settings: /wp-admin/admin.php?page=zerobscrm-plugin-settings&tab=transactions + $res['status_bool'] = ( 'all' === $this->getTransactionStatusesToInclude() || in_array( $res['status'], $this->getTransactionStatusesToInclude() ) ? 1 : -1 ); + + // type further categorised here, because JS etc. needs it in non-lingual + $res['type_accounting'] = $this->transactionAccountingType( $res['type'] ); + + $res['ref'] = $this->stripSlashes( $obj->zbst_ref ); + $res['origin'] = $this->stripSlashes( $obj->zbst_origin ); + $res['parent'] = (int) $obj->zbst_parent; + $res['hash'] = $this->stripSlashes( $obj->zbst_hash ); + $res['title'] = $obj->zbst_title === null ? '' : $this->stripSlashes( $obj->zbst_title ); + $res['desc'] = $this->stripSlashes( $obj->zbst_desc ); + $res['date'] = (int) $obj->zbst_date; + // well this naming convention makes this confusing... lol: // + $res['date_date'] = ( isset( $obj->zbst_date ) && $obj->zbst_date > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbst_date ) : false; + $res['customer_ip'] = $this->stripSlashes( $obj->zbst_customer_ip ); + $res['currency'] = $this->stripSlashes( $obj->zbst_currency ); + $res['net'] = $this->stripSlashes( $obj->zbst_net ); + $res['fee'] = $this->stripSlashes( $obj->zbst_fee ); + $res['discount'] = $this->stripSlashes( $obj->zbst_discount ); + $res['shipping'] = $this->stripSlashes( $obj->zbst_shipping ); + $res['shipping_taxes'] = $this->stripSlashes( $obj->zbst_shipping_taxes ); + $res['shipping_tax'] = $this->stripSlashes( $obj->zbst_shipping_tax ); + $res['taxes'] = $this->stripSlashes( $obj->zbst_taxes ); + $res['tax'] = $this->stripSlashes( $obj->zbst_tax ); + $res['total'] = $this->stripSlashes( $obj->zbst_total ); + $res['date_paid'] = $obj->zbst_date_paid === null ? null : (int) $obj->zbst_date_paid; + $res['date_paid_date'] = ( isset( $obj->zbst_date_paid ) && $obj->zbst_date_paid > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbst_date_paid ) : false; + $res['date_completed'] = $obj->zbst_date_completed === null ? null : (int) $obj->zbst_date_completed; + $res['date_completed_date'] = ( isset( $obj->zbst_date_completed ) && $obj->zbst_date_completed > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbst_date_completed ) : false; + $res['created'] = (int) $obj->zbst_created; + $res['created_date'] = ( isset( $obj->zbst_created ) && $obj->zbst_created > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbst_created, false, true ) : false; + $res['lastupdated'] = (int) $obj->zbst_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbst_lastupdated ) && $obj->zbst_lastupdated > 0 ) ? zeroBSCRM_locale_utsToDatetime( $obj->zbst_lastupdated ) : false; + + // custom fields - tidy any that are present: + if ($withCustomFields) $res = $this->tidyAddCustomFields( ZBS_TYPE_TRANSACTION, $obj, $res, false ); - 'obj_type' => ZBS_TYPE_TRANSACTION, - 'obj_id' => $id, - 'obj_source' => 'all', + } - )); + return $res; + } - } + /** + * Tidies a row from a database result containing the columns external_source_uids and external_source_sources. + * The result is a formatted HTML string. + * + * @param object $row (DB row containing the columns external_source_uids and external_source_sources) + * + * @return string Formatted HTML string for the external sources. + */ + private function tidy_external_sources( $row ) { + if ( $row->external_source_uids == null && $row->external_source_sources == null ) { + return ''; + } + $external_source_uids = explode( "\n", $row->external_source_uids ); + $external_source_sources = explode( "\n", $row->external_source_sources ); + $external_source_strings = array_map( + function ( $source, $uid ) { + $source_title = zeroBS_getExternalSourceTitle( $source, $uid ); + // Formats the default zeroBS_getExternalSourceTitle string to look better in the table. + $source_title_explode = explode( '
', $source_title, 2 ); + if ( count( $source_title_explode ) === 2 ) { + // Removes the trailing ':' from the source. E.g. 'WooCommerce:' becomes 'WooCommerce'. + $source_title_source = rtrim( $source_title_explode[0], ':' ); + return "{$source_title_explode[1]} ({$source_title_source})"; + } else { + return $source_title; + } + }, + $external_source_sources, + $external_source_uids + ); - $del = zeroBSCRM_db2_deleteGeneric($id,'transactions'); + return implode( '
', $external_source_strings ); + } - #} Add to automator - zeroBSCRM_FireInternalAutomator('transaction.delete',array( - 'id'=>$id, - 'saveOrphans'=>$saveOrphans - )); + /** + * Takes a transaction status (e.g. Sale or Credit Note), and returns debit/credit :) + * wrapper that should be used throughout for inferring accounting direction for a transaction + * + * @param int objtype + * @param int objid + * @param string key + * + * @return array transaction meta result + */ + public function transactionAccountingType( $transaction_type = 'Sale' ) { - $this->events_manager->transaction()->deleted( $id ); + if ( ! empty( $transaction_type ) ) { - return $del; + if ( in_array( $transaction_type, array( __( 'Refund', 'zero-bs-crm' ), __( 'Credit Note', 'zero-bs-crm' ) ) ) ) { + return 'credit'; + } + } - } + return 'debit'; + } - return false; + /** + * Wrapper, use $this->getTransactionMeta($contactID,$key) for easy retrieval of singular transaction + * Simplifies $this->getMeta + * + * @param int objtype + * @param int objid + * @param string key + * + * @return array transaction meta result + */ + public function getTransactionMeta( $id = -1, $key = '', $default = false ) { - } + global $zbs; - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array transaction (clean obj) - */ - private function tidy_transaction($obj=false,$withCustomFields=false){ + if ( ! empty( $key ) ) { - $res = false; + return $this->DAL()->getMeta( + array( - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = $obj->zbs_owner; - - $res['status'] = $this->stripSlashes($obj->zbst_status); - $res['type'] = $this->stripSlashes($obj->zbst_type); - - // status categorisation (basically did it succeed?) - // this is dictated by Transaction Status settings: /wp-admin/admin.php?page=zerobscrm-plugin-settings&tab=transactions - $res['status_bool'] = ( 'all' === $this->getTransactionStatusesToInclude() || in_array( $res['status'], $this->getTransactionStatusesToInclude() ) ? 1 : -1 ); - - // type further categorised here, because JS etc. needs it in non-lingual - $res['type_accounting'] = $this->transactionAccountingType($res['type']); - - $res['ref'] = $this->stripSlashes($obj->zbst_ref); - $res['origin'] = $this->stripSlashes($obj->zbst_origin); - $res['parent'] = (int)$obj->zbst_parent; - $res['hash'] = $this->stripSlashes($obj->zbst_hash); - $res['title'] = is_null($obj->zbst_title)?'':$this->stripSlashes($obj->zbst_title); - $res['desc'] = $this->stripSlashes($obj->zbst_desc); - $res['date'] = (int)$obj->zbst_date; - // well this naming convention makes this confusing... lol: // - $res['date_date'] = (isset($obj->zbst_date) && $obj->zbst_date > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbst_date) : false; - $res['customer_ip'] = $this->stripSlashes($obj->zbst_customer_ip); - $res['currency'] = $this->stripSlashes($obj->zbst_currency); - $res['net'] = $this->stripSlashes($obj->zbst_net); - $res['fee'] = $this->stripSlashes($obj->zbst_fee); - $res['discount'] = $this->stripSlashes($obj->zbst_discount); - $res['shipping'] = $this->stripSlashes($obj->zbst_shipping); - $res['shipping_taxes'] = $this->stripSlashes($obj->zbst_shipping_taxes); - $res['shipping_tax'] = $this->stripSlashes($obj->zbst_shipping_tax); - $res['taxes'] = $this->stripSlashes($obj->zbst_taxes); - $res['tax'] = $this->stripSlashes($obj->zbst_tax); - $res['total'] = $this->stripSlashes($obj->zbst_total); - $res['date_paid'] = is_null( $obj->zbst_date_paid ) ? null : (int)$obj->zbst_date_paid; - $res['date_paid_date'] = (isset($obj->zbst_date_paid) && $obj->zbst_date_paid > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbst_date_paid) : false; - $res['date_completed'] = is_null( $obj->zbst_date_completed ) ? null : (int)$obj->zbst_date_completed; - $res['date_completed_date'] = (isset($obj->zbst_date_completed) && $obj->zbst_date_completed > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbst_date_completed) : false; - $res['created'] = (int)$obj->zbst_created; - $res['created_date'] = (isset($obj->zbst_created) && $obj->zbst_created > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbst_created,false,true) : false; - $res['lastupdated'] = (int)$obj->zbst_lastupdated; - $res['lastupdated_date'] = (isset($obj->zbst_lastupdated) && $obj->zbst_lastupdated > 0) ? zeroBSCRM_locale_utsToDatetime($obj->zbst_lastupdated) : false; - - // custom fields - tidy any that are present: - if ($withCustomFields) $res = $this->tidyAddCustomFields(ZBS_TYPE_TRANSACTION,$obj,$res,false); - - } - - - return $res; - - - } - - /** - * Tidies a row from a database result containing the columns external_source_uids and external_source_sources. - * The result is a formatted HTML string. - * - * @param object $row (DB row containing the columns external_source_uids and external_source_sources) - * - * @return string Formatted HTML string for the external sources. - */ - private function tidy_external_sources( $row ) { - if ($row->external_source_uids == null && $row->external_source_sources == null) { - return ""; - } - $external_source_uids = explode("\n", $row->external_source_uids); - $external_source_sources = explode("\n", $row->external_source_sources); - $external_source_strings = array_map( - function($source, $uid) { - $source_title = zeroBS_getExternalSourceTitle( $source, $uid ); - // Formats the default zeroBS_getExternalSourceTitle string to look better in the table. - $source_title_explode = explode( "
", $source_title, 2 ); - if ( count($source_title_explode) === 2 ) { - // Removes the trailing ':' from the source. E.g. 'WooCommerce:' becomes 'WooCommerce'. - $source_title_source = rtrim($source_title_explode[0], ":"); - return "{$source_title_explode[1]} ({$source_title_source})"; - } else { - return $source_title; - } - }, - $external_source_sources, - $external_source_uids - ); - - return implode( '
', $external_source_strings ); - } - - /** - * Takes a transaction status (e.g. Sale or Credit Note), and returns debit/credit :) - * wrapper that should be used throughout for inferring accounting direction for a transaction - * - * @param int objtype - * @param int objid - * @param string key - * - * @return array transaction meta result - */ - public function transactionAccountingType( $transaction_type='Sale' ){ - - if ( !empty( $transaction_type ) ){ - - if ( in_array( $transaction_type, array( __( 'Refund', 'zero-bs-crm' ), __( 'Credit Note', 'zero-bs-crm' ) ) ) ){ - return 'credit'; - } + 'objtype' => ZBS_TYPE_TRANSACTION, + 'objid' => $id, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, + 'ignoreowner' => true, // for now !! - } + ) + ); - return 'debit'; - } + } + return $default; + } - /** - * Wrapper, use $this->getTransactionMeta($contactID,$key) for easy retrieval of singular transaction - * Simplifies $this->getMeta - * - * @param int objtype - * @param int objid - * @param string key - * - * @return array transaction meta result - */ - public function getTransactionMeta($id=-1,$key='',$default=false){ + /** + * Returns a Transaction's tag array + * + * @param int id Transaction ID + * + * @return mixed + */ + public function getTransactionTags( $id = -1 ) { - global $zbs; + global $zbs; - if (!empty($key)){ + $id = (int) $id; - return $this->DAL()->getMeta(array( + if ( $id > 0 ) { - 'objtype' => ZBS_TYPE_TRANSACTION, - 'objid' => $id, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default, - 'ignoreowner' => true // for now !! + return $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_TRANSACTION, + 'objid' => $id, + ) + ); - )); + } - } + return false; + } - return $default; - } + /** + * Returns a reference against a transaction + * + * @param int id transaction ID + * + * @return string transaction ref + */ + public function get_transaction_ref( $transaction_id = -1 ) { + global $zbs; - /** - * Returns a Transaction's tag array - * - * @param int id Transaction ID - * - * @return mixed - */ - public function getTransactionTags($id=-1){ + return $this->DAL()->getFieldByID( + array( + 'id' => $transaction_id, + 'objtype' => ZBS_TYPE_TRANSACTION, + 'colname' => 'zbst_ref', + 'ignoreowner' => true, + ) + ); + } - global $zbs; + /** + * Returns an ownerid against a transaction + * + * @param int id transaction ID + * + * @return int transaction owner id + */ + public function getTransactionOwner( $id = -1 ) { - $id = (int)$id; + global $zbs; - if ($id > 0){ + $id = (int) $id; - return $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_TRANSACTION,'objid'=>$id)); + if ( $id > 0 ) { - } + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_TRANSACTION, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); - return false; - - } + } + return false; + } - - /** - * Returns a reference against a transaction - * - * @param int id transaction ID - * - * @return string transaction ref - */ - public function get_transaction_ref( $transaction_id = -1 ){ + /** + * Returns an array of contacts associtaed with a transaction + * + * @param int id transaction ID + * + * @return array contacts assocatied with transaction + */ + public function get_transaction_contacts( $transaction_id ) { + + return $this->DAL()->contacts->getContacts( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_TRANSACTION, + 'hasObjIDLinkedTo' => $transaction_id, + ) + ); + } - global $zbs; + /** + * Returns an invoice associtaed with a transaction + * + * @param int id transaction ID + * + * @return array $invoice + */ + public function get_transaction_invoice_id( $transaction_id ) { - return $this->DAL()->getFieldByID( array( - 'id' => $transaction_id, - 'objtype' => ZBS_TYPE_TRANSACTION, - 'colname' => 'zbst_ref', - 'ignoreowner' => true - )); - - } + return $this->DAL()->getFirstIDLinkedToObj( + array( + 'objtypefrom' => ZBS_TYPE_TRANSACTION, + 'objtypeto' => ZBS_TYPE_INVOICE, + 'objfromid' => $transaction_id, - /** - * Returns an ownerid against a transaction - * - * @param int id transaction ID - * - * @return int transaction owner id - */ - public function getTransactionOwner($id=-1){ + ) + ); + } - global $zbs; + /** + * Returns an status against a transaction + * + * @param int id transaction ID + * + * @return string transaction status string + */ + public function getTransactionStatus( $id = -1 ) { - $id = (int)$id; + global $zbs; - if ($id > 0){ + $id = (int) $id; - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_TRANSACTION, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); - - } - - return false; - - } + if ( $id > 0 ) { + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_TRANSACTION, + 'colname' => 'zbst_status', + 'ignoreowner' => true, + ) + ); - - /** - * Returns an array of contacts associtaed with a transaction - * - * @param int id transaction ID - * - * @return array contacts assocatied with transaction - */ - public function get_transaction_contacts( $transaction_id ){ - - return $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_TRANSACTION, - 'hasObjIDLinkedTo'=>$transaction_id - )); - - } - - /** - * Returns an invoice associtaed with a transaction - * - * @param int id transaction ID - * - * @return array $invoice - */ - public function get_transaction_invoice_id( $transaction_id ){ + } - return $this->DAL()->getFirstIDLinkedToObj(array( - - 'objtypefrom' => ZBS_TYPE_TRANSACTION, - 'objtypeto' => ZBS_TYPE_INVOICE, - 'objfromid' => $transaction_id, - - )); - - } - - - /** - * Returns an status against a transaction - * - * @param int id transaction ID - * - * @return string transaction status string - */ - public function getTransactionStatus($id=-1){ - - global $zbs; - - $id = (int)$id; - - if ($id > 0){ - - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_TRANSACTION, - 'colname' => 'zbst_status', - 'ignoreowner'=>true)); - - } - - return false; - - } - - /** - * returns the transaction statuses to include in "total value" as per the setting on - * admin.php?page=zerobscrm-plugin-settings&tab=transactions - * - * @return array - */ - function getTransactionStatusesToInclude(){ - - // load (accept from cache) - $setting = $this->DAL()->setting( 'transinclude_status', 'all', true ); - - if (is_string($setting) && strpos($setting, ',') > 0){ - - return explode(',', $setting); - } elseif (is_array($setting)){ + return false; + } - return $setting; - - } + /** + * returns the transaction statuses to include in "total value" as per the setting on + * admin.php?page=zerobscrm-plugin-settings&tab=transactions + * + * @return array + */ + function getTransactionStatusesToInclude() { - return 'all'; - - } + // load (accept from cache) + $setting = $this->DAL()->setting( 'transinclude_status', 'all', true ); - /** - * returns an SQL query addition which will allow filtering of transactions - * that should be included in "total value" fields - * admin.php?page=zerobscrm-plugin-settings&tab=transactions - * - * @param string $table_alias_sql - if using a table alias pass that here, e.g. `transactions`. - * @return array - */ - function getTransactionStatusesToIncludeQuery( $table_alias_sql = '' ){ + if ( is_string( $setting ) && strpos( $setting, ',' ) > 0 ) { + return explode( ',', $setting ); + } elseif ( is_array( $setting ) ) { - // first we get the setting - $transaction_statuses = $this->getTransactionStatusesToInclude(); - - // next we build the SQL - // note that (in a legacy way) getTransactionStatusesToInclude() returns a string 'all' - // .. if all transactions are selected - // .. in that case there's no SQL to return as all statuses count. - $query_addition = ''; - if ( is_array( $transaction_statuses ) && count( $transaction_statuses ) > 0 ){ + return $setting; - // create escaped csv - $transaction_statuses_str = $this->build_csv( $transaction_statuses ); + } - // build return sql - $query_addition = ' AND ' . $table_alias_sql . 'zbst_status IN ('.$transaction_statuses_str.')'; + return 'all'; + } - } + /** + * returns an SQL query addition which will allow filtering of transactions + * that should be included in "total value" fields + * admin.php?page=zerobscrm-plugin-settings&tab=transactions + * + * @param string $table_alias_sql - if using a table alias pass that here, e.g. `transactions`. + * @return array + */ + function getTransactionStatusesToIncludeQuery( $table_alias_sql = '' ) { - return $query_addition; + // first we get the setting + $transaction_statuses = $this->getTransactionStatusesToInclude(); - } + // next we build the SQL + // note that (in a legacy way) getTransactionStatusesToInclude() returns a string 'all' + // .. if all transactions are selected + // .. in that case there's no SQL to return as all statuses count. + $query_addition = ''; + if ( is_array( $transaction_statuses ) && count( $transaction_statuses ) > 0 ) { + // create escaped csv + $transaction_statuses_str = $this->build_csv( $transaction_statuses ); + // build return sql + $query_addition = ' AND ' . $table_alias_sql . 'zbst_status IN (' . $transaction_statuses_str . ')'; - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * This does so based on the objectModel! - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - private function db_ready_transaction($obj=false){ + } - // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); + return $query_addition; + } - } + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * This does so based on the objectModel! + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + private function db_ready_transaction( $obj = false ) { - /** - * Takes full object and makes a "list view" boiled down version - * Used to generate listview objs - * - * @param array $obj (clean obj) - * - * @return array (listview ready obj) - */ - public function listViewObj($transaction=false,$columnsRequired=array()){ + // use the generic? (override here if necessary) + return $this->db_ready_obj( $obj ); + } - if (is_array($transaction) && isset($transaction['id'])){ + /** + * Takes full object and makes a "list view" boiled down version + * Used to generate listview objs + * + * @param array $obj (clean obj) + * + * @return array (listview ready obj) + */ + public function listViewObj( $transaction = false, $columnsRequired = array() ) { - $resArr = $transaction; + if ( is_array( $transaction ) && isset( $transaction['id'] ) ) { - // a lot of this is legacy 7 ? substr($transaction['orderid'],0,7)."..." : $transaction['orderid']; - // order id now = ref (use proper field) - //$resArr['id'] = $transaction['id']; - $resArr['status'] = ucfirst($transaction['status']); + // a lot of this is legacy format(zeroBSCRM_getDateFormat()); - // USE proper field $resArr['added'] = $formatted_date; + $resArr['total'] = zeroBSCRM_formatCurrency( $resArr['total'] ); + // $resArr['orderid'] = strlen($transaction['orderid']) > 7 ? substr($transaction['orderid'],0,7)."..." : $transaction['orderid']; + // order id now = ref (use proper field) + // $resArr['id'] = $transaction['id']; + $resArr['status'] = ucfirst( $transaction['status'] ); - #} Convert $contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer - $resArr['customer'] = zeroBSCRM_getSimplyFormattedContact($transaction['contact'],(in_array('assignedobj', $columnsRequired))); + // This wasn't working: $d = new DateTime($transaction['meta']['date']); + // ... so I added the correct field (post_date) to getTransactions and piped in here + // $d = new DateTime($transaction['date']); + // $formatted_date = $d->format(zeroBSCRM_getDateFormat()); + // USE proper field $resArr['added'] = $formatted_date; - #} Convert $contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer - $resArr['company'] = zeroBSCRM_getSimplyFormattedCompany($transaction['company'],(in_array('assignedobj', $columnsRequired))); + #} Convert $contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer + $resArr['customer'] = zeroBSCRM_getSimplyFormattedContact( $transaction['contact'], ( in_array( 'assignedobj', $columnsRequired ) ) ); - #} Tags - //if (in_array('tagged', $columnsRequired)){ + #} Convert $contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer + $resArr['company'] = zeroBSCRM_getSimplyFormattedCompany( $transaction['company'], ( in_array( 'assignedobj', $columnsRequired ) ) ); - // $resArr['tags'] = $transaction['tags']; + #} Tags + // if (in_array('tagged', $columnsRequired)){ - //} + // $resArr['tags'] = $transaction['tags']; - return $resArr; + // } - } + return $resArr; - return false; + } - } + return false; + } - // =========== / TRANSACTION ======================================================= - // =============================================================================== + // =========== / TRANSACTION ======================================================= + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.ObjectLayer.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.ObjectLayer.php index 558c8225ef60..cf62cd20be7f 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.ObjectLayer.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.ObjectLayer.php @@ -1,5 +1,6 @@ -> Object Class -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Object Class + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_ObjectLayer { - protected $objectType = -1; // e.g. ZBS_TYPE_CONTACT - protected $objectModel = -1; // array('DBFIELD(e.g. zbs_owner'=>array('Local field (e.g. owner)','format (int)')) - // formats: - // int = (int) - // uts = uts + converted to locale date _datestr - // - protected $objectTableName = -1; - protected $objectFieldCSV = -1; // assumes model wont change mid-load :) - protected $include_in_templating = false; // if true, object types fields will be accessible in templating - - // hardtyped list of types this object type is commonly linked to - // Note that as of 4.1.1 this mechanism is only used via DAL3.Export to know what typical links to look for, it is not a hard rule, or currently respected anywhere else. - // e.g. Invoice object type may be commonly linked to 'contact' or 'company' object types - protected $linkedToObjectTypes = array(); + protected $objectType = -1; // e.g. ZBS_TYPE_CONTACT + protected $objectModel = -1; // array('DBFIELD(e.g. zbs_owner'=>array('Local field (e.g. owner)','format (int)')) + // formats: + // int = (int) + // uts = uts + converted to locale date _datestr + // + protected $objectTableName = -1; + protected $objectFieldCSV = -1; // assumes model wont change mid-load :) + protected $include_in_templating = false; // if true, object types fields will be accessible in templating + + // hardtyped list of types this object type is commonly linked to + // Note that as of 4.1.1 this mechanism is only used via DAL3.Export to know what typical links to look for, it is not a hard rule, or currently respected anywhere else. + // e.g. Invoice object type may be commonly linked to 'contact' or 'company' object types + protected $linkedToObjectTypes = array(); /** This field is used to store name clashes so we can change custom field names * with name clashes in function `fix_name_clash_if_needed()` @@ -65,697 +64,734 @@ class zbsDAL_ObjectLayer { */ protected $objectIncludesAddresses; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase - function __construct($args=array()) { - - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - //'tag' => false, - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - // check objectModel + err if not legit - - // ==== AUTO TRANSLATION - // Any labels passed with $objectModel need passing through translation :) - if (is_array($this->objectModel)) foreach ($this->objectModel as $key => $fieldArr){ - - if (isset($fieldArr['label'])) $fieldArr['label'] = __($fieldArr['label'],'zero-bs-crm'); - if (isset($fieldArr['placeholder'])) $fieldArr['placeholder'] = __($fieldArr['placeholder'],'zero-bs-crm'); - if (isset($fieldArr['options']) && is_array($fieldArr['options'])){ - - $newOptions = array(); - foreach ($fieldArr['options'] as $o){ - $newOptions[] =__($o,'zero-bs-crm'); - } - $fieldArr['options'] = $newOptions; - unset($newOptions); - } - - } - - } - - // return core vars - public function objTableName(){ - return $this->objectTableName; - } - public function objType(){ - return $this->objectType; - } - public function objModel($appendCustomFields=false){ - return $this->objectModel; - } - public function linkedToObjectTypes(){ - return $this->linkedToObjectTypes; - } - public function is_included_in_templating(){ - return $this->include_in_templating; - } - - // return the objModel with additional custom fields as if they were db-ready fields - // Note: This is a bridging function currently only used in DAL3.Exports.php, - // ... a refactoring of the dbmodel+customfields+globalfieldarrays is necessary pre v4.0 - // ... in mean time, avoid usage in the initial field setup linkages - // - // Note: Also the format of the custom field arr will differ from the objmodel field arr's - // ... to distinguish, look for attribute 'custom-field' - // ... but probably best to generally avoid usage of this function until reconciled the above note. - // see gh-253 - public function objModelIncCustomFields(){ - - global $zbs; - - $customFields = false; - $model = $this->objectModel; - - // turn ZBS_TYPE_CONTACT (1) into "contact" - $typeStr = $this->DAL()->objTypeKey($this->objectType); - - // Direct retrieval v3+ - if (!empty($typeStr)) $customFields = $zbs->DAL->setting('customfields_'.$typeStr,array()); - - // if is an obj which has custom field capacity: - if (isset($customFields) && is_array($customFields)){ - - // add to model - foreach ($customFields as $fieldKey => $field){ - - // Unpacks csv options and sets 'custom-field' attr - // Adds it to arr - // ignores potential collisions (e.g. custom field with key 'status'), these should be blocked by UI - $model[$fieldKey] = zeroBSCRM_customFields_processCustomField($field); - - } - - - } - - // if obj also has addresses, check for address custom fields - // Adapted from DAL3.Fields.php - // see gh-253 - if ($this->includesAddressFields()){ - - #} Retrieve - $addrCustomFields = $zbs->DAL->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); - - #} Addresses - if (is_array($addrCustomFields) && count($addrCustomFields) > 0){ - - $cfIndx = 1; - foreach ($addrCustomFields as $fieldKey => $field){ - - // unpacks csv options and sets 'custom-field' attr - $fieldO = zeroBSCRM_customFields_processCustomField($field); - - // splice them in to the end of the e.g. 'second address' group - - // Addr1 - - // for this specifically, we also add '[area]' - $fieldO['area'] = 'Main Address'; - - // find index - $mainAddrIndx = -1; $i = 0; foreach ($model as $k => $f) { - if (isset($f['area']) && $f['area'] == 'Main Address') $mainAddrIndx = $i; - $i++; - } - - // splice - $mainAddrIndx++; // req - $model = array_merge( - array_slice( $model, 0, $mainAddrIndx, true ), - array( 'addr_'.$fieldKey => $fieldO ), - array_slice( $model, $mainAddrIndx, null, true ) - ); - - // Addr2 - - // change area - $fieldO['area'] = 'Second Address'; - - // find index - $secAddrIndx = -1; $i = 0; foreach ($model as $k => $f) { - if (isset($f['area']) && $f['area'] == 'Second Address') $secAddrIndx = $i; - $i++; - } - - // splice - $secAddrIndx++; // req - $model = array_merge( - array_slice( $model, 0, $secAddrIndx, true ), - array( 'secaddr_'.$fieldKey => $fieldO ), - array_slice( $model, $secAddrIndx, null, true ) - ); - - } - - } - - } - - return $model; - - } - - - /** - * returns bool depending on whether object has custom fields setup - * - * - * @return bool - */ - public function hasCustomFields($includeHidden=false){ - - global $zbs; + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + // 'tag' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + // check objectModel + err if not legit + + // ==== AUTO TRANSLATION + // Any labels passed with $objectModel need passing through translation :) + if ( is_array( $this->objectModel ) ) { + foreach ( $this->objectModel as $key => $fieldArr ) { + + if ( isset( $fieldArr['label'] ) ) { + $fieldArr['label'] = __( $fieldArr['label'], 'zero-bs-crm' ); + } + if ( isset( $fieldArr['placeholder'] ) ) { + $fieldArr['placeholder'] = __( $fieldArr['placeholder'], 'zero-bs-crm' ); + } + if ( isset( $fieldArr['options'] ) && is_array( $fieldArr['options'] ) ) { + + $newOptions = array(); + foreach ( $fieldArr['options'] as $o ) { + $newOptions[] = __( $o, 'zero-bs-crm' ); + } + $fieldArr['options'] = $newOptions; + unset( $newOptions ); + } + } + } + } - $fieldsToHide = array(); + // return core vars + public function objTableName() { + return $this->objectTableName; + } + public function objType() { + return $this->objectType; + } + public function objModel( $appendCustomFields = false ) { + return $this->objectModel; + } + public function linkedToObjectTypes() { + return $this->linkedToObjectTypes; + } + public function is_included_in_templating() { + return $this->include_in_templating; + } - // turn ZBS_TYPE_CONTACT (1) into "contact" - $typeStr = $this->DAL()->objTypeKey($this->objectType); + // return the objModel with additional custom fields as if they were db-ready fields + // Note: This is a bridging function currently only used in DAL3.Exports.php, + // ... a refactoring of the dbmodel+customfields+globalfieldarrays is necessary pre v4.0 + // ... in mean time, avoid usage in the initial field setup linkages + // + // Note: Also the format of the custom field arr will differ from the objmodel field arr's + // ... to distinguish, look for attribute 'custom-field' + // ... but probably best to generally avoid usage of this function until reconciled the above note. + // see gh-253 + public function objModelIncCustomFields() { - // any to hide? - if (!$includeHidden){ + global $zbs; - $fieldHideOverrides = $zbs->settings->get('fieldhides'); - if (isset($fieldHideOverrides[$typeStr])) $fieldsToHide = $fieldHideOverrides[$typeStr]; + $customFields = false; + $model = $this->objectModel; - } + // turn ZBS_TYPE_CONTACT (1) into "contact" + $typeStr = $this->DAL()->objTypeKey( $this->objectType ); - // Direct retrieval v3+ - if (!empty($typeStr)) { + // Direct retrieval v3+ + if ( ! empty( $typeStr ) ) { + $customFields = $zbs->DAL->setting( 'customfields_' . $typeStr, array() ); + } - $customFields = $zbs->DAL->setting('customfields_'.$typeStr,array()); + // if is an obj which has custom field capacity: + if ( isset( $customFields ) && is_array( $customFields ) ) { - // got custom fields? - if (isset($customFields) && is_array($customFields)){ + // add to model + foreach ( $customFields as $fieldKey => $field ) { - // cycle through custom fields - foreach ($customFields as $fieldKey => $field){ + // Unpacks csv options and sets 'custom-field' attr + // Adds it to arr + // ignores potential collisions (e.g. custom field with key 'status'), these should be blocked by UI + $model[ $fieldKey ] = zeroBSCRM_customFields_processCustomField( $field ); - // hidden? - if ($includeHidden || !in_array($fieldKey, $fieldsToHide)){ + } + } - return true; + // if obj also has addresses, check for address custom fields + // Adapted from DAL3.Fields.php + // see gh-253 + if ( $this->includesAddressFields() ) { + + #} Retrieve + $addrCustomFields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); + + #} Addresses + if ( is_array( $addrCustomFields ) && count( $addrCustomFields ) > 0 ) { + + $cfIndx = 1; + foreach ( $addrCustomFields as $fieldKey => $field ) { + + // unpacks csv options and sets 'custom-field' attr + $fieldO = zeroBSCRM_customFields_processCustomField( $field ); + + // splice them in to the end of the e.g. 'second address' group + + // Addr1 + + // for this specifically, we also add '[area]' + $fieldO['area'] = 'Main Address'; + + // find index + $mainAddrIndx = -1; + $i = 0; foreach ( $model as $k => $f ) { + if ( isset( $f['area'] ) && $f['area'] == 'Main Address' ) { + $mainAddrIndx = $i; + } + ++$i; + } + + // splice + ++$mainAddrIndx; // req + $model = array_merge( + array_slice( $model, 0, $mainAddrIndx, true ), + array( 'addr_' . $fieldKey => $fieldO ), + array_slice( $model, $mainAddrIndx, null, true ) + ); + + // Addr2 + + // change area + $fieldO['area'] = 'Second Address'; + + // find index + $secAddrIndx = -1; + $i = 0; foreach ( $model as $k => $f ) { + if ( isset( $f['area'] ) && $f['area'] == 'Second Address' ) { + $secAddrIndx = $i; + } + ++$i; + } + + // splice + ++$secAddrIndx; // req + $model = array_merge( + array_slice( $model, 0, $secAddrIndx, true ), + array( 'secaddr_' . $fieldKey => $fieldO ), + array_slice( $model, $secAddrIndx, null, true ) + ); + + } + } + } - } + return $model; + } - } + /** + * returns bool depending on whether object has custom fields setup + * + * @return bool + */ + public function hasCustomFields( $includeHidden = false ) { - } + global $zbs; - } + $fieldsToHide = array(); - return false; + // turn ZBS_TYPE_CONTACT (1) into "contact" + $typeStr = $this->DAL()->objTypeKey( $this->objectType ); - } + // any to hide? + if ( ! $includeHidden ) { + $fieldHideOverrides = $zbs->settings->get( 'fieldhides' ); + if ( isset( $fieldHideOverrides[ $typeStr ] ) ) { + $fieldsToHide = $fieldHideOverrides[ $typeStr ]; + } + } - /** - * returns custom fields for an object - * .. optionally excluding hidden (from fieldsort page) - * - * - * @return array custom fields - */ - public function getCustomFields($includeHidden=false){ + // Direct retrieval v3+ + if ( ! empty( $typeStr ) ) { - global $zbs; + $customFields = $zbs->DAL->setting( 'customfields_' . $typeStr, array() ); - $returnCustomFields = array(); $fieldsToHide = array(); + // got custom fields? + if ( isset( $customFields ) && is_array( $customFields ) ) { - // turn ZBS_TYPE_CONTACT (1) into "contact" - $typeStr = $this->DAL()->objTypeKey($this->objectType); + // cycle through custom fields + foreach ( $customFields as $fieldKey => $field ) { - // any to hide? - if (!$includeHidden){ + // hidden? + if ( $includeHidden || ! in_array( $fieldKey, $fieldsToHide ) ) { - $fieldHideOverrides = $zbs->settings->get('fieldhides'); - if (isset($fieldHideOverrides[$typeStr])) $fieldsToHide = $fieldHideOverrides[$typeStr]; + return true; - } + } + } + } + } - // Direct retrieval v3+ - if (!empty($typeStr)) { + return false; + } - $customFields = $zbs->DAL->setting('customfields_'.$typeStr,array()); + /** + * returns custom fields for an object + * .. optionally excluding hidden (from fieldsort page) + * + * @return array custom fields + */ + public function getCustomFields( $includeHidden = false ) { - // got custom fields? - if (isset($customFields) && is_array($customFields)){ + global $zbs; - // cycle through custom fields - foreach ($customFields as $fieldKey => $field){ + $returnCustomFields = array(); + $fieldsToHide = array(); - // hidden? - if ( $includeHidden || !$fieldsToHide || ( is_array( $fieldsToHide ) && ! in_array( $fieldKey, $fieldsToHide ) ) ) { + // turn ZBS_TYPE_CONTACT (1) into "contact" + $typeStr = $this->DAL()->objTypeKey( $this->objectType ); - // Unpacks csv options and sets 'custom-field' attr - // Adds it to arr - $returnCustomFields[$fieldKey] = $field; + // any to hide? + if ( ! $includeHidden ) { - } + $fieldHideOverrides = $zbs->settings->get( 'fieldhides' ); + if ( isset( $fieldHideOverrides[ $typeStr ] ) ) { + $fieldsToHide = $fieldHideOverrides[ $typeStr ]; + } + } - } + // Direct retrieval v3+ + if ( ! empty( $typeStr ) ) { - } + $customFields = $zbs->DAL->setting( 'customfields_' . $typeStr, array() ); - } + // got custom fields? + if ( isset( $customFields ) && is_array( $customFields ) ) { - return $returnCustomFields; + // cycle through custom fields + foreach ( $customFields as $fieldKey => $field ) { - } + // hidden? + if ( $includeHidden || ! $fieldsToHide || ( is_array( $fieldsToHide ) && ! in_array( $fieldKey, $fieldsToHide ) ) ) { - public function includesAddressFields(){ + // Unpacks csv options and sets 'custom-field' attr + // Adds it to arr + $returnCustomFields[ $fieldKey ] = $field; - if (isset($this->objectIncludesAddresses)) return true; + } + } + } + } - return false; - } + return $returnCustomFields; + } - public function DAL(){ + public function includesAddressFields() { - // hmm this is reference to a kind of 'parent' but not parent class. not sure best reference here. - // (to get back to $zbs->DAL) - // ... this allows us to centralise the reference in all children classes, at least, but probs a more oop logical way to do this - // is mostly helpers like buildWhere etc. but also other DAL funcs. - global $zbs; - return $zbs->DAL; - } + if ( isset( $this->objectIncludesAddresses ) ) { + return true; + } - // internal sql helpers - private function objFieldCSV(){ - - // assumes model wont change :) - if ($this->objectFieldCSV == -1 || $this->objectFieldCSV == ''){ + return false; + } - $x = ''; if (is_array($this->objectModel)) foreach ($this->objectModel as $k => $v) { - if (!empty($x)) $x .= ','; - $x .= $k; - } + public function DAL() { - $this->objectFieldCSV = $x; + // hmm this is reference to a kind of 'parent' but not parent class. not sure best reference here. + // (to get back to $zbs->DAL) + // ... this allows us to centralise the reference in all children classes, at least, but probs a more oop logical way to do this + // is mostly helpers like buildWhere etc. but also other DAL funcs. + global $zbs; + return $zbs->DAL; + } - } + // internal sql helpers + private function objFieldCSV() { - return $this->objectFieldCSV; - } + // assumes model wont change :) + if ( $this->objectFieldCSV == -1 || $this->objectFieldCSV == '' ) { + $x = ''; if ( is_array( $this->objectModel ) ) { + foreach ( $this->objectModel as $k => $v ) { + if ( ! empty( $x ) ) { + $x .= ','; + } + $x .= $k; + } + } - // basic get any (first 10 paged) - public function get($args=array()){ + $this->objectFieldCSV = $x; - // hmm this is reference to a kind of 'parent' but not parent class. not sure best reference here. - // (to get back to $zbs->DAL) - global $zbs; + } - #} =========== LOAD ARGS ============== - $defaultArgs = array( + return $this->objectFieldCSV; + } - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, - 'perPage' => 10, + // basic get any (first 10 paged) + public function get( $args = array() ) { + + // hmm this is reference to a kind of 'parent' but not parent class. not sure best reference here. + // (to get back to $zbs->DAL) + global $zbs; + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, + 'perPage' => 10, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} ========== CHECK FIELDS ============ - #} ========== CHECK FIELDS ============ + // always ignore owner for now (settings global) + $ignoreowner = true; - // always ignore owner for now (settings global) - $ignoreowner = true; - - #} ========= / CHECK FIELDS =========== + #} ========= / CHECK FIELDS =========== - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} Build query + #} Build query $query = 'SELECT ' . $this->objFieldCSV() . ' FROM ' . $this->objectTableName; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - #} ============= WHERE ================ - - - #} ============ / WHERE =============== - - #} Build out any WHERE clauses - $wheresArr= $zbs->DAL2->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE - - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$zbs->DAL2->tools-->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $zbs->DAL2->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $zbs->DAL2->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $zbs->DAL2->buildWhereStr($whereStr,$additionalWhere) . $zbs->DAL2->buildSort($sortByField,$sortOrder) . $zbs->DAL2->buildPaging($page,$perPage); - - try { - - #} Prep & run query - $queryObj = $zbs->DAL2->prepare($query,$params); - $potentialRes = $zbs->DAL2->get_results($queryObj, OBJECT); - - } catch (Exception $e){ - - #} General SQL Err - $zbs->DAL2->catchSQLError($e); - - } - - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { - - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy (simple) - $resArr = $this->tidy($resDataLine); - $res[] = $resArr; - - } - } - - return $res; - - } - - - // takes $this->objectModel and converts any applicable fields - // into old-form (legacy) $globalFieldArr (as used to be hard-typed in Fields.php Pre DAL3) - #} #FIELDLOADING - public function generateFieldsGlobalArr(){ - - if (isset($this->objectModel) && is_array($this->objectModel)){ - - // build it - $retArr = array(); - - // cycle through fields - foreach ($this->objectModel as $dal3key => $fieldModel){ + #} ============= WHERE ================ - // if they have 'input_type' then they're designed to be loaded into the global field var - // .. if not, they're DB-only / loaded elsewhere stuff - if (is_array($fieldModel) && isset($fieldModel['input_type'])){ + #} ============ / WHERE =============== - // should be loaded. Build it. - $retArr[$dal3key] = array(); + #} Build out any WHERE clauses + $wheresArr = $zbs->DAL2->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - // Old format as follows: - /*'fname' => array( - 'text', // input type - __('First Name',"zero-bs-crm"), // label - 'e.g. John', // placeholder - // extra options: +- - 'options'=>array('Mr', 'Mrs', 'Ms', 'Miss', 'Dr', 'Prof','Mr & Mrs'), - 'essential' => true - 'area'=>__('Main Address',"zero-bs-crm"), - 'migrate'=>'addresses' - 'opt'=>'secondaddress', - ) */ - - // map them in - - // input type = [0] - $retArr[$dal3key][0] = $fieldModel['input_type']; - - // input label = [1] - $retArr[$dal3key][1] = ''; - if ( isset( $fieldModel['label'] ) ) { - $retArr[$dal3key][1] = __( $fieldModel['label'], 'zero-bs-crm' ); - $second_address_label = zeroBSCRM_getSetting( 'secondaddresslabel' ); - if ( empty( $second_address_label ) ) { - $second_address_label = __( 'Second Address', 'zero-bs-crm' ); - } - if( !empty( $fieldModel['area'] ) && $fieldModel['area'] == 'Second Address' ) { - $retArr[$dal3key][1] .= ' (' . esc_html( $second_address_label ) . ')'; - } - } - - // input placeholder = [2] - $retArr[$dal3key][2] = (isset($fieldModel['placeholder'])) ? $fieldModel['placeholder'] : ''; - - // extra options (all key-referenced) - //if (isset($fieldModel['options'])) $retArr[$dal3key]['options'] = $fieldModel['options']; - // [options] == [3] in old global obj model world - if (isset($fieldModel['options'])) $retArr[$dal3key][3] = $fieldModel['options']; - - if (isset($fieldModel['essential'])) $retArr[$dal3key]['essential'] = $fieldModel['essential']; - if (isset($fieldModel['area'])) $retArr[$dal3key]['area'] = $fieldModel['area']; - if (isset($fieldModel['migrate'])) $retArr[$dal3key]['migrate'] = $fieldModel['migrate']; - if (isset($fieldModel['opt'])) $retArr[$dal3key]['opt'] = $fieldModel['opt']; - if (isset($fieldModel['nocolumn'])) $retArr[$dal3key]['nocolumn'] = $fieldModel['nocolumn']; - if (isset($fieldModel['default'])) $retArr[$dal3key]['default'] = $fieldModel['default']; - - // should all have (where different from dal3key): - if (isset($fieldModel['dal1key'])) $retArr[$dal3key]['dal1key'] = $fieldModel['dal1key']; - - } - - } // / foreach field - - // return built fieldGlobalArr (should mimic old DAL1/2 Fields.php) - return $retArr; - - } - - return array(); - - } - - // returns a translation matrix of DAL1key => DAL3key, where possible, using 'dal1key' attribute in data model - public function getDAL1toDAL3ConversionMatrix(){ - - $ret = array(); - - if (isset($this->objectModel) && is_array($this->objectModel)){ - - //foreach ($arraySource as $k => $v){ - foreach ($this->objectModel as $v3Key => $fieldObj){ - - if (isset($fieldObj['dal1key'])){ - - $ret[$fieldObj['dal1key']] = $v3Key; + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $zbs->DAL2->tools-- > ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $zbs->DAL2->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $zbs->DAL2->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - } + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $zbs->DAL2->buildWhereStr( $whereStr, $additionalWhere ) . $zbs->DAL2->buildSort( $sortByField, $sortOrder ) . $zbs->DAL2->buildPaging( $page, $perPage ); - } + try { - } + #} Prep & run query + $queryObj = $zbs->DAL2->prepare( $query, $params ); + $potentialRes = $zbs->DAL2->get_results( $queryObj, OBJECT ); - return $ret; + } catch ( Exception $e ) { - } + #} General SQL Err + $zbs->DAL2->catchSQLError( $e ); + } - // generic get X (by ID) - // designed to be overriden by each child. - public function getSingle($ID=-1){ + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - return false; + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - } + // tidy (simple) + $resArr = $this->tidy( $resDataLine ); + $res[] = $resArr; - /** - * Helper to retrieve Custom Fields with Data for an object - * - * @return array summarised custom fields including values, for object - */ - public function getSingleCustomFields($ID=-1,$includeHidden=false){ + } + } - global $zbs; + return $res; + } - if ($ID > 0){ + // takes $this->objectModel and converts any applicable fields + // into old-form (legacy) $globalFieldArr (as used to be hard-typed in Fields.php Pre DAL3) + #} #FIELDLOADING + public function generateFieldsGlobalArr() { + + if ( isset( $this->objectModel ) && is_array( $this->objectModel ) ) { + + // build it + $retArr = array(); + + // cycle through fields + foreach ( $this->objectModel as $dal3key => $fieldModel ) { + + // if they have 'input_type' then they're designed to be loaded into the global field var + // .. if not, they're DB-only / loaded elsewhere stuff + if ( is_array( $fieldModel ) && isset( $fieldModel['input_type'] ) ) { + + // should be loaded. Build it. + $retArr[ $dal3key ] = array(); + + // Old format as follows: + /* + 'fname' => array( + 'text', // input type + __('First Name',"zero-bs-crm"), // label + 'e.g. John', // placeholder + // extra options: +- + 'options'=>array('Mr', 'Mrs', 'Ms', 'Miss', 'Dr', 'Prof','Mr & Mrs'), + 'essential' => true + 'area'=>__('Main Address',"zero-bs-crm"), + 'migrate'=>'addresses' + 'opt'=>'secondaddress', + ) */ + + // map them in + + // input type = [0] + $retArr[ $dal3key ][0] = $fieldModel['input_type']; + + // input label = [1] + $retArr[ $dal3key ][1] = ''; + if ( isset( $fieldModel['label'] ) ) { + $retArr[ $dal3key ][1] = __( $fieldModel['label'], 'zero-bs-crm' ); + $second_address_label = zeroBSCRM_getSetting( 'secondaddresslabel' ); + if ( empty( $second_address_label ) ) { + $second_address_label = __( 'Second Address', 'zero-bs-crm' ); + } + if ( ! empty( $fieldModel['area'] ) && $fieldModel['area'] == 'Second Address' ) { + $retArr[ $dal3key ][1] .= ' (' . esc_html( $second_address_label ) . ')'; + } + } + + // input placeholder = [2] + $retArr[ $dal3key ][2] = ( isset( $fieldModel['placeholder'] ) ) ? $fieldModel['placeholder'] : ''; + + // extra options (all key-referenced) + // if (isset($fieldModel['options'])) $retArr[$dal3key]['options'] = $fieldModel['options']; + // [options] == [3] in old global obj model world + if ( isset( $fieldModel['options'] ) ) { + $retArr[ $dal3key ][3] = $fieldModel['options']; + } + + if ( isset( $fieldModel['essential'] ) ) { + $retArr[ $dal3key ]['essential'] = $fieldModel['essential']; + } + if ( isset( $fieldModel['area'] ) ) { + $retArr[ $dal3key ]['area'] = $fieldModel['area']; + } + if ( isset( $fieldModel['migrate'] ) ) { + $retArr[ $dal3key ]['migrate'] = $fieldModel['migrate']; + } + if ( isset( $fieldModel['opt'] ) ) { + $retArr[ $dal3key ]['opt'] = $fieldModel['opt']; + } + if ( isset( $fieldModel['nocolumn'] ) ) { + $retArr[ $dal3key ]['nocolumn'] = $fieldModel['nocolumn']; + } + if ( isset( $fieldModel['default'] ) ) { + $retArr[ $dal3key ]['default'] = $fieldModel['default']; + } + + // should all have (where different from dal3key): + if ( isset( $fieldModel['dal1key'] ) ) { + $retArr[ $dal3key ]['dal1key'] = $fieldModel['dal1key']; + } + } + } // / foreach field + + // return built fieldGlobalArr (should mimic old DAL1/2 Fields.php) + return $retArr; - // retrieve custom fields - $customFields = $this->getCustomFields($includeHidden); + } - // retrieve object data - $objectData = $this->getSingle($ID); if (!is_array($objectData)) $objectData = array(); + return array(); + } - // Build return - $return = array(); - if (is_array($customFields)) foreach($customFields as $k => $v){ + // returns a translation matrix of DAL1key => DAL3key, where possible, using 'dal1key' attribute in data model + public function getDAL1toDAL3ConversionMatrix() { - $return[] = array( - 'id' => $v[3], - 'name' => $v[1], - 'value' => (isset($objectData[$v[3]]) ? $objectData[$v[3]] : ''), - 'type' => $v[0] - ); + $ret = array(); - } + if ( isset( $this->objectModel ) && is_array( $this->objectModel ) ) { - return $return; + // foreach ($arraySource as $k => $v){ + foreach ( $this->objectModel as $v3Key => $fieldObj ) { - } + if ( isset( $fieldObj['dal1key'] ) ) { - return false; - } + $ret[ $fieldObj['dal1key'] ] = $v3Key; - // generic get X (by IDs) - // designed to be overriden by each child. - public function getIDList($IDs=array()){ + } + } + } - return false; + return $ret; + } - } + // generic get X (by ID) + // designed to be overriden by each child. + public function getSingle( $ID = -1 ) { - // generic get X (EVERYTHING) - // designed to be overriden by each child. - // expect heavy load! - public function getAll($IDs=array()){ + return false; + } - return false; + /** + * Helper to retrieve Custom Fields with Data for an object + * + * @return array summarised custom fields including values, for object + */ + public function getSingleCustomFields( $ID = -1, $includeHidden = false ) { - } + global $zbs; - // generic get count of (EVERYTHING) - // designed to be overriden by each child. - public function getFullCount(){ + if ( $ID > 0 ) { - return false; + // retrieve custom fields + $customFields = $this->getCustomFields( $includeHidden ); - } + // retrieve object data + $objectData = $this->getSingle( $ID ); + if ( ! is_array( $objectData ) ) { + $objectData = array(); + } - // Ownership - simplistic GET owner of obj - public function getOwner($objID=-1){ + // Build return + $return = array(); + if ( is_array( $customFields ) ) { + foreach ( $customFields as $k => $v ) { - // check - if ($objID < 1) return false; - - return $this->DAL()->getObjectOwner(array( - - 'objID' => $objID, - 'objTypeID' => $this->objectType + $return[] = array( + 'id' => $v[3], + 'name' => $v[1], + 'value' => ( isset( $objectData[ $v[3] ] ) ? $objectData[ $v[3] ] : '' ), + 'type' => $v[0], + ); - )); + } + } - } + return $return; - // Ownership - simplistic SET owner of obj - public function setOwner($objID=-1,$ownerID=-1){ + } - // check - if ($objID < 1 || $ownerID < 1) return false; - - // set owner - return $this->DAL()->setObjectOwner(array( - - 'objID' => $objID, - 'objTypeID' => $this->objectType, - 'ownerID' => $ownerID + return false; + } - )); + // generic get X (by IDs) + // designed to be overriden by each child. + public function getIDList( $IDs = array() ) { - } + return false; + } - + // generic get X (EVERYTHING) + // designed to be overriden by each child. + // expect heavy load! + public function getAll( $IDs = array() ) { + return false; + } - /** - * Wrapper, use $this->updateMeta($objid,$key,$val) for easy update of obj meta :) - * (Uses built in type) - * - * @param string key - * @param string value - * - * @return bool result - */ - public function updateMeta($objid=-1,$key='',$val=''){ - - if (!empty($key) && isset($this->objectType) && $this->objectType > 0){ // && !empty($val) + // generic get count of (EVERYTHING) + // designed to be overriden by each child. + public function getFullCount() { - return $this->DAL()->addUpdateMeta(array( + return false; + } - 'data' => array( + // Ownership - simplistic GET owner of obj + public function getOwner( $objID = -1 ) { - 'objid' => $objid, - 'objtype' => $this->objectType, - 'key' => $key, - 'val' => $val - ) + // check + if ( $objID < 1 ) { + return false; + } - )); + return $this->DAL()->getObjectOwner( + array( - } + 'objID' => $objID, + 'objTypeID' => $this->objectType, - return false; - } - + ) + ); + } - /** - * tidy's the object from wp db into clean array - * ... also converts uts to local datetime etc. politely - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - public function tidy($obj=false){ + // Ownership - simplistic SET owner of obj + public function setOwner( $objID = -1, $ownerID = -1 ) { - global $zbs; + // check + if ( $objID < 1 || $ownerID < 1 ) { + return false; + } - $res = false; + // set owner + return $this->DAL()->setObjectOwner( + array( - if (isset($obj->ID)){ + 'objID' => $objID, + 'objTypeID' => $this->objectType, + 'ownerID' => $ownerID, - // THESE must be standard :) - $res = array(); - $res['id'] = (int)$obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - $res['owner'] = (int)$obj->zbs_owner; + ) + ); + } - // cycle through + pull in - foreach ($this->objectModel as $dbkey => $val){ + /** + * Wrapper, use $this->updateMeta($objid,$key,$val) for easy update of obj meta :) + * (Uses built in type) + * + * @param string key + * @param string value + * + * @return bool result + */ + public function updateMeta( $objid = -1, $key = '', $val = '' ) { - // if not already set - if (!isset($res[$val['fieldname']])){ + if ( ! empty( $key ) && isset( $this->objectType ) && $this->objectType > 0 ) { // && !empty($val) - switch ($val['format']){ + return $this->DAL()->addUpdateMeta( + array( - case 'int': + 'data' => array( - $res[$val['fieldname']] = (int)$obj->$dbkey; - break; + 'objid' => $objid, + 'objtype' => $this->objectType, + 'key' => $key, + 'val' => $val, + ), - case 'uts': + ) + ); - // normal return - $res[$val['fieldname']] = (int)$obj->$dbkey; + } - // auto add locale str - $res[$val['fieldname'].'_datestr'] = zeroBSCRM_locale_utsToDatetime($obj->$dbkey); - break; + return false; + } - default: + /** + * tidy's the object from wp db into clean array + * ... also converts uts to local datetime etc. politely + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + public function tidy( $obj = false ) { - $res[$val['fieldname']] = $obj->$dbkey; - break; + global $zbs; + $res = false; - } + if ( isset( $obj->ID ) ) { - } + // THESE must be standard :) + $res = array(); + $res['id'] = (int) $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['owner'] = (int) $obj->zbs_owner; + // cycle through + pull in + foreach ( $this->objectModel as $dbkey => $val ) { - } + // if not already set + if ( ! isset( $res[ $val['fieldname'] ] ) ) { + switch ( $val['format'] ) { - } // if is obj id + case 'int': + $res[ $val['fieldname'] ] = (int) $obj->$dbkey; + break; + case 'uts': + // normal return + $res[ $val['fieldname'] ] = (int) $obj->$dbkey; - return $res; + // auto add locale str + $res[ $val['fieldname'] . '_datestr' ] = zeroBSCRM_locale_utsToDatetime( $obj->$dbkey ); + break; + default: + $res[ $val['fieldname'] ] = $obj->$dbkey; + break; - } + } + } + } + } // if is obj id + return $res; + } /** * Offers generic custom field tidying, where an obj and it's cleaned version are passed @@ -768,580 +804,566 @@ public function tidy($obj=false){ * * @return array (clean obj) */ - public function tidyAddCustomFields($objTypeID=ZBS_TYPE_CONTACT,$obj=false,$res=false,$includeAddrCustomFields=false){ - - // vague catch - if ($obj == false || $res == false) return $res; - - #} Retrieve any cf - $customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>$objTypeID)); - - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ - - // custom field (e.g. 'third name') it'll be passed here as 'third-name' - // ... problem is mysql does not like that :) so we have to chage here: - // in this case we REVERSE this: prepend cf's with cf_ and we switch - for _ - // ... by using $cKey below, instead of cK - $cKey = 'cf_'.str_replace('-','_',$cK); - - $res[$cK] = ''; - - // if normal - if (isset($obj->$cK)) $res[$cK] = $this->stripSlashes($obj->$cK); - - // if cf - if (isset($obj->$cKey)) $res[$cK] = $this->stripSlashes($obj->$cKey); - - // if date_type, format - if ( isset($cF[0] ) && $cF[0] === 'date') { - - // make a _date field - if ( '' === $res[$cK] ) { - $res[$cK.'_cfdate'] = ''; - } else { - $res[$cK.'_cfdate'] = zeroBSCRM_date_i18n( -1, $res[$cK], false, true ); - $res[$cK.'_datetime_str'] = jpcrm_uts_to_datetime_str( $res[$cK] ); - $res[$cK.'_date_str'] = jpcrm_uts_to_date_str( $res[$cK] ); - } - } - } - - #} Retrieve addr custfiedls - $addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); - - if (is_array($addrCustomFields)) foreach ($addrCustomFields as $cK => $cF){ - - // v2: - //$cKN = (int)$cK+1; - //$cKey = 'addr_cf'.$cKN; - //$cKey2 = 'secaddr_cf'.$cKN; - // v3: - //$cKey = 'addr_'.$cK; - //$cKey2 = 'secaddr_'.$cK; - // v4: - // These keys were causing alias collisions in mysql when keys ended up like 'addr_house-type' - // ... where the sort couldn't be fired for that key due to the - character - // ... so from 4.0.7+ we processed these adding a prefix `addrcf_` (and `secaddrcf_`) and replacing - for _ - $cKey = 'addrcf_'.str_replace('-','_',$cK); - $cKey2 = 'secaddrcf_'.str_replace('-','_',$cK); - - // Note we still want to return as `addr_house-type` not `addrcf_house_type` - $res['addr_'.$cK] = ''; - $res['secaddr_'.$cK] = ''; - - // retrieve - if (isset($obj->$cKey)) $res['addr_'.$cK] = $this->stripSlashes($obj->$cKey); - if (isset($obj->$cKey2)) $res['secaddr_'.$cK] = $this->stripSlashes($obj->$cKey2); - - // if date_type, format - if (isset($cF[0]) && $cF[0] == 'date'){ - - // make a _date field - if ( isset( $res['addr_' . $cK] ) ) { - $res['addr_' . $cK . '_cfdate'] = zeroBSCRM_date_i18n( -1, $res['addr_' . $cK], false, true ); - $res['addr_' . $cK . '_datetime_str'] = jpcrm_uts_to_datetime_str( $res['addr_' . $cK] ); - $res['addr_' . $cK . '_date_str'] = jpcrm_uts_to_date_str( $res['addr_' . $cK] ); - } - if ( isset( $res['secaddr_' . $cK] ) ) { - $res['secaddr_' . $cK . '_cfdate'] = zeroBSCRM_date_i18n( -1, $res['secaddr_' . $cK], false, true ); - $res['secaddr_' . $cK . '_datetime_str'] = jpcrm_uts_to_datetime_str( $res['secaddr_' . $cK] ); - $res['secaddr_' . $cK . '_date_str'] = jpcrm_uts_to_date_str( $res['secaddr_' . $cK] ); - } - - } - - } - - return $res; - - } - - /** - * this takes a dataArray passed for update/insert and works through - * the fields, checking against the obj model for compliance - * initially this only includes max_len checks as fix for gh-270 - * - * @param array $dataArr (pre-insert obj) - * - * @return bool - */ - public function wpdbChecks($dataArr=array()){ - - // req. - global $zbs; - - if ( $this->objectType > 0 && is_array( $dataArr ) && isset( $this->objectDBPrefix ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - // new return - $retArr = $dataArr; - - foreach ($dataArr as $key => $val){ - - // use $objectDBPrefix to retrieve the objmodel key - // zbsi_id_override => id_override - $fieldKey = str_replace($this->objectDBPrefix,'', $key); - - // max length check? - if (!empty($fieldKey) && isset($this->objectModel[$fieldKey]) && isset($this->objectModel[$fieldKey]['max_len'])){ - - // check length - if (strlen($val) > $this->objectModel[$fieldKey]['max_len']){ - - // > max_len - // .. abbreviate - $retArr[$key] = substr($val, 0, ($this->objectModel[$fieldKey]['max_len']-3)).'...'; - - // Add notice - $label = $fieldKey; if (isset($this->objectModel[$fieldKey]['label'])) $label = $this->objectModel[$fieldKey]['label']; - $msg = __('The value for the field:','zero-bs-crm').' "'.$label.'" '.__('was too long and has been abbreviated','zero-bs-crm'); - $zbs->DAL->addError(305,$this->objectType,$msg,$fieldKey); - - } - - } - - } - - // return (possibly modified arr) - return $retArr; - - } - - return $dataArr; - - } + public function tidyAddCustomFields( $objTypeID = ZBS_TYPE_CONTACT, $obj = false, $res = false, $includeAddrCustomFields = false ) { - /** - * this takes the current database insert/update or any object - * and validates it against the dbmodel for that objtype for uniqueness - * e.g. if a field in the dbmodel has force_unique, it's checked that that field is in fact unique, - * returning false if so - * Note: Blanks side-step this check if attribute 'can_be_blank', but are still are still subject to 'not_empty' check - * ... (verifyNonEmptyValues) if that attribute is specified in the obj model - * - * This'll also add an error to the stack, if it can - * - * @param array $obj (clean obj) - * - * @return bool - */ - public function verifyUniqueValues($objArr=array(),$id=-1){ - - // req. - global $zbs; - - $checksFailed = array(); - - if ( $this->objectType > 0 && is_array( $objArr ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - // DAL3+ we now have proper object models, so can check for 'force_unique' flags against field - - // get an obj model, if set - // note: importantly, v2->v3 migration in v3.0 uses DAL2 objModel drop-in function here, so be aware this may be used during v2->v3 migration - $potentialModel = $zbs->DAL->objModel($this->objectType); - - // will be objlayer model if set - if (is_array($potentialModel)){ - - // cycle through each field verify where necessary - foreach ($potentialModel as $fieldKey => $fieldDetail){ - - // there's a few we ignore :) - if (in_array($fieldKey, array('ID','zbs_site','zbs_team','zbs_owner'))) continue; - - // verify unique fields are unique + unused - // note. If 'can_be_blank' is also set against the field, blank doesn't get checked here - if (isset($fieldDetail['force_unique']) && $fieldDetail['force_unique']){ - - if (isset($fieldDetail['can_be_blank']) && $fieldDetail['can_be_blank'] && empty($objArr[$fieldKey])){ - - // field is blank, and is allowed to be! - - } else { - - // needs to ensure field is unique. - - // get existing id, if set - $whereArr = array(); // colname zbsc_email - $whereArr['uniquecheck'] = array($fieldDetail['fieldname'],'=','%s',$objArr[$fieldKey]); - - $potentialID = $zbs->DAL->getFieldByWHERE(array( - 'objtype' => $this->objectType, // ZBS_TYPE_CONTACT - 'colname' => 'ID', - 'where' => $whereArr, - 'ignoreowner' => true)); + // vague catch + if ( $obj == false || $res == false ) { + return $res; + } - // catch dupes (exists, but it's not this) - if ($potentialID > 0 && $potentialID != $id){ + #} Retrieve any cf + $customFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => $objTypeID ) ); + + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { + + // custom field (e.g. 'third name') it'll be passed here as 'third-name' + // ... problem is mysql does not like that :) so we have to chage here: + // in this case we REVERSE this: prepend cf's with cf_ and we switch - for _ + // ... by using $cKey below, instead of cK + $cKey = 'cf_' . str_replace( '-', '_', $cK ); + + $res[ $cK ] = ''; + + // if normal + if ( isset( $obj->$cK ) ) { + $res[ $cK ] = $this->stripSlashes( $obj->$cK ); + } + + // if cf + if ( isset( $obj->$cKey ) ) { + $res[ $cK ] = $this->stripSlashes( $obj->$cKey ); + } + + // if date_type, format + if ( isset( $cF[0] ) && $cF[0] === 'date' ) { + + // make a _date field + if ( '' === $res[ $cK ] ) { + $res[ $cK . '_cfdate' ] = ''; + } else { + $res[ $cK . '_cfdate' ] = zeroBSCRM_date_i18n( -1, $res[ $cK ], false, true ); + $res[ $cK . '_datetime_str' ] = jpcrm_uts_to_datetime_str( $res[ $cK ] ); + $res[ $cK . '_date_str' ] = jpcrm_uts_to_date_str( $res[ $cK ] ); + } + } + } + } - // pass back the failed field. - $checksFailed[$fieldKey] = $fieldDetail; + #} Retrieve addr custfiedls + $addrCustomFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); + + if ( is_array( $addrCustomFields ) ) { + foreach ( $addrCustomFields as $cK => $cF ) { + + // v2: + // $cKN = (int)$cK+1; + // $cKey = 'addr_cf'.$cKN; + // $cKey2 = 'secaddr_cf'.$cKN; + // v3: + // $cKey = 'addr_'.$cK; + // $cKey2 = 'secaddr_'.$cK; + // v4: + // These keys were causing alias collisions in mysql when keys ended up like 'addr_house-type' + // ... where the sort couldn't be fired for that key due to the - character + // ... so from 4.0.7+ we processed these adding a prefix `addrcf_` (and `secaddrcf_`) and replacing - for _ + $cKey = 'addrcf_' . str_replace( '-', '_', $cK ); + $cKey2 = 'secaddrcf_' . str_replace( '-', '_', $cK ); + + // Note we still want to return as `addr_house-type` not `addrcf_house_type` + $res[ 'addr_' . $cK ] = ''; + $res[ 'secaddr_' . $cK ] = ''; + + // retrieve + if ( isset( $obj->$cKey ) ) { + $res[ 'addr_' . $cK ] = $this->stripSlashes( $obj->$cKey ); + } + if ( isset( $obj->$cKey2 ) ) { + $res[ 'secaddr_' . $cK ] = $this->stripSlashes( $obj->$cKey2 ); + } + + // if date_type, format + if ( isset( $cF[0] ) && $cF[0] == 'date' ) { + + // make a _date field + if ( isset( $res[ 'addr_' . $cK ] ) ) { + $res[ 'addr_' . $cK . '_cfdate' ] = zeroBSCRM_date_i18n( -1, $res[ 'addr_' . $cK ], false, true ); + $res[ 'addr_' . $cK . '_datetime_str' ] = jpcrm_uts_to_datetime_str( $res[ 'addr_' . $cK ] ); + $res[ 'addr_' . $cK . '_date_str' ] = jpcrm_uts_to_date_str( $res[ 'addr_' . $cK ] ); + } + if ( isset( $res[ 'secaddr_' . $cK ] ) ) { + $res[ 'secaddr_' . $cK . '_cfdate' ] = zeroBSCRM_date_i18n( -1, $res[ 'secaddr_' . $cK ], false, true ); + $res[ 'secaddr_' . $cK . '_datetime_str' ] = jpcrm_uts_to_datetime_str( $res[ 'secaddr_' . $cK ] ); + $res[ 'secaddr_' . $cK . '_date_str' ] = jpcrm_uts_to_date_str( $res[ 'secaddr_' . $cK ] ); + } + } + } + } - } + return $res; + } - } + /** + * this takes a dataArray passed for update/insert and works through + * the fields, checking against the obj model for compliance + * initially this only includes max_len checks as fix for gh-270 + * + * @param array $dataArr (pre-insert obj) + * + * @return bool + */ + public function wpdbChecks( $dataArr = array() ) { - } + // req. + global $zbs; - } // / foreach + if ( $this->objectType > 0 && is_array( $dataArr ) && isset( $this->objectDBPrefix ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } // / if has model + // new return + $retArr = $dataArr; + foreach ( $dataArr as $key => $val ) { - } + // use $objectDBPrefix to retrieve the objmodel key + // zbsi_id_override => id_override + $fieldKey = str_replace( $this->objectDBPrefix, '', $key ); - // got any fails? - if (count($checksFailed) > 0) { + // max length check? + if ( ! empty( $fieldKey ) && isset( $this->objectModel[ $fieldKey ] ) && isset( $this->objectModel[ $fieldKey ]['max_len'] ) ) { - // can't update, some non-uniques. + // check length + if ( strlen( $val ) > $this->objectModel[ $fieldKey ]['max_len'] ) { - // set reason msg - if ( is_array( $checksFailed ) ) { - foreach ( $checksFailed as $fieldKey => $fieldDetail ) { - $fk = $fieldKey; - if ( isset( $fieldDetail['label'] ) ) { - $fk = $fieldDetail['label']; - } - if( $fk === 'id_override' ) { - $msg = __('Duplicated reference. The reference should be unique', 'zero-bs-crm'); - } else { - $msg = __('The value for the field:', 'zero-bs-crm') . ' "' . $fk . '" ' . __('was not unique (exists)', 'zero-bs-crm'); - } + // > max_len + // .. abbreviate + $retArr[ $key ] = substr( $val, 0, ( $this->objectModel[ $fieldKey ]['max_len'] - 3 ) ) . '...'; - $zbs->DAL->addError( 301, $this->objectType, $msg, $fieldKey ); - } - } + // Add notice + $label = $fieldKey; + if ( isset( $this->objectModel[ $fieldKey ]['label'] ) ) { + $label = $this->objectModel[ $fieldKey ]['label']; + } + $msg = __( 'The value for the field:', 'zero-bs-crm' ) . ' "' . $label . '" ' . __( 'was too long and has been abbreviated', 'zero-bs-crm' ); + $zbs->DAL->addError( 305, $this->objectType, $msg, $fieldKey ); - // return fail - return false; + } + } + } - } // / fails unique field verify + // return (possibly modified arr) + return $retArr; - return true; + } - } + return $dataArr; + } - /** - * this takes the current database insert/update or any object - * and validates it against the dbmodel for that objtype for empties - * e.g. if a field in the dbmodel has not_empty, it's checked that that field is in fact not empty - * returning false if so - * Note this is inverse to 'can_be_blank' flag - * - * This'll also add an error to the stack, if it can - * - * @param array $obj (clean obj) - * - * @return bool - */ - public function verifyNonEmptyValues($objArr=array()){ + /** + * this takes the current database insert/update or any object + * and validates it against the dbmodel for that objtype for uniqueness + * e.g. if a field in the dbmodel has force_unique, it's checked that that field is in fact unique, + * returning false if so + * Note: Blanks side-step this check if attribute 'can_be_blank', but are still are still subject to 'not_empty' check + * ... (verifyNonEmptyValues) if that attribute is specified in the obj model + * + * This'll also add an error to the stack, if it can + * + * @param array $obj (clean obj) + * + * @return bool + */ + public function verifyUniqueValues( $objArr = array(), $id = -1 ) { - // req. - global $zbs; + // req. + global $zbs; - $checksFailed = array(); + $checksFailed = array(); if ( $this->objectType > 0 && is_array( $objArr ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // DAL3+ we now have proper object models, so can check for 'force_unique' flags against field - - // get an obj model, if set - // note: importantly, v2->v3 migration in v3.0 uses DAL2 objModel drop-in function here, so be aware this may be used during v2->v3 migration - $potentialModel = $zbs->DAL->objModel($this->objectType); + // DAL3+ we now have proper object models, so can check for 'force_unique' flags against field - // will be objlayer model if set - if (is_array($potentialModel)){ + // get an obj model, if set + // note: importantly, v2->v3 migration in v3.0 uses DAL2 objModel drop-in function here, so be aware this may be used during v2->v3 migration + $potentialModel = $zbs->DAL->objModel( $this->objectType ); - // cycle through each field verify where necessary - foreach ($potentialModel as $fieldKey => $fieldDetail){ + // will be objlayer model if set + if ( is_array( $potentialModel ) ) { - // verify fields are not empty - // note. This ignores 'can_be_blank', if is somehow set despite setting not_empty - if (isset($fieldDetail['not_empty']) && $fieldDetail['not_empty']){ + // cycle through each field verify where necessary + foreach ( $potentialModel as $fieldKey => $fieldDetail ) { - // needs to ensure field is not empty - if (empty($objArr[$fieldKey])){ + // there's a few we ignore :) + if ( in_array( $fieldKey, array( 'ID', 'zbs_site', 'zbs_team', 'zbs_owner' ) ) ) { + continue; + } - // pass back the failed field. - $checksFailed[$fieldKey] = $fieldDetail; + // verify unique fields are unique + unused + // note. If 'can_be_blank' is also set against the field, blank doesn't get checked here + if ( isset( $fieldDetail['force_unique'] ) && $fieldDetail['force_unique'] ) { - } + if ( isset( $fieldDetail['can_be_blank'] ) && $fieldDetail['can_be_blank'] && empty( $objArr[ $fieldKey ] ) ) { + // field is blank, and is allowed to be! - } + } else { - } // / foreach + // needs to ensure field is unique. - } // / if has model + // get existing id, if set + $whereArr = array(); // colname zbsc_email + $whereArr['uniquecheck'] = array( $fieldDetail['fieldname'], '=', '%s', $objArr[ $fieldKey ] ); + $potentialID = $zbs->DAL->getFieldByWHERE( + array( + 'objtype' => $this->objectType, // ZBS_TYPE_CONTACT + 'colname' => 'ID', + 'where' => $whereArr, + 'ignoreowner' => true, + ) + ); - } + // catch dupes (exists, but it's not this) + if ( $potentialID > 0 && $potentialID != $id ) { - // got any fails? - if (count($checksFailed) > 0){ + // pass back the failed field. + $checksFailed[ $fieldKey ] = $fieldDetail; - // can't update, some empties. + } + } + } + } // / foreach - // set reason msg - if (is_array($checksFailed)) foreach ($checksFailed as $fieldKey => $fieldDetail){ - $fk = $fieldKey; if (isset($fieldDetail['label'])) $fk = $fieldDetail['label']; - $msg = __('The field:','zero-bs-crm').' "'.$fk.'" '.__('is required','zero-bs-crm'); - $zbs->DAL->addError(304,$this->objectType,$msg,$fieldKey); - } + } // / if has model - // return fail - return false; - - } // / fails non blank field verify - - return true; - - } - - - /** - * remove any non-db fields from the object - * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') - * and returns array like array('owner'=>1,'fname'=>'x') - * - * @param array $obj (clean obj) - * - * @return array (db ready arr) - */ - public function db_ready_obj($obj=false){ - - global $zbs; - - // here it has to use the KEY which is without prefix (e.g. status, not zbsc_status) :) - if (isset($this->objectModel) && is_array($this->objectModel)){ - - $ret = array(); - if (is_array($obj)){ - - foreach ($this->objectModel as $fKey => $fObj){ - - if (isset($obj[$fKey])) $ret[$fKey] = $obj[$fKey]; - - } - - // gross backward compat - long may this die. - if ($zbs->db2CompatabilitySupport) $ret['meta'] = $ret; - - } - - } - - return $ret; - - - } - - /** - * genericified link array of id's with this obj - * Takes current area (e.g. EVENT) as first type, and assigns objlinks EVENT -> $toObjType - * - * @param int $objectID (int of this obj id) - * @param array $objectIDsArr (array of ints (IDs)) - NOTE: can pass 'unset' as str to wipe links - * @param int $toObjectType (int of obj link type) - * - * @return bool of action - */ - public function addUpdateObjectLinks($objectID=-1,$objectIDsArr=false,$toObjectType=false){ - if ($toObjectType > 0 && $objectID > 0){ - - // GENERICIFIED OBJ LINKS - if (isset($objectIDsArr) && is_array($objectIDsArr) && count($objectIDsArr) > 0){ - - // replace existing - $this->DAL()->addUpdateObjLinks(array( - 'objtypefrom' => $this->objectType, - 'objtypeto' => $toObjectType, - 'objfromid' => $objectID, - 'objtoids' => $objectIDsArr, - 'mode' => 'replace')); - - return true; + } - } else if (isset($objectIDsArr) && $objectIDsArr == 'unset') { + // got any fails? + if ( count( $checksFailed ) > 0 ) { + + // can't update, some non-uniques. + + // set reason msg + if ( is_array( $checksFailed ) ) { + foreach ( $checksFailed as $fieldKey => $fieldDetail ) { + $fk = $fieldKey; + if ( isset( $fieldDetail['label'] ) ) { + $fk = $fieldDetail['label']; + } + if ( $fk === 'id_override' ) { + $msg = __( 'Duplicated reference. The reference should be unique', 'zero-bs-crm' ); + } else { + $msg = __( 'The value for the field:', 'zero-bs-crm' ) . ' "' . $fk . '" ' . __( 'was not unique (exists)', 'zero-bs-crm' ); + } + + $zbs->DAL->addError( 301, $this->objectType, $msg, $fieldKey ); + } + } - // wipe previous links - $deleted = $this->DAL()->deleteObjLinks(array( - 'objtypefrom' => $this->objectType, - 'objtypeto' => $toObjectType, - 'objfromid' => $objectID)); // where id = + // return fail + return false; - return true; + } // / fails unique field verify - } + return true; + } - } + /** + * this takes the current database insert/update or any object + * and validates it against the dbmodel for that objtype for empties + * e.g. if a field in the dbmodel has not_empty, it's checked that that field is in fact not empty + * returning false if so + * Note this is inverse to 'can_be_blank' flag + * + * This'll also add an error to the stack, if it can + * + * @param array $obj (clean obj) + * + * @return bool + */ + public function verifyNonEmptyValues( $objArr = array() ) { + // req. + global $zbs; - return false; - } - + $checksFailed = array(); - // =============================================================================== - // =========== DAL2 WRAPPERS ===================================================== - // These are dumb, and pass back directly to parent $zbs->DAL equivilents, centralising them - // ... this is so we can keep $this->lazyTable etc. usage which is simpler than $this->DAL()->lazyTable + if ( $this->objectType > 0 && is_array( $objArr ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // DAL3+ we now have proper object models, so can check for 'force_unique' flags against field - public function lazyTable($objType=-1){ + // get an obj model, if set + // note: importantly, v2->v3 migration in v3.0 uses DAL2 objModel drop-in function here, so be aware this may be used during v2->v3 migration + $potentialModel = $zbs->DAL->objModel( $this->objectType ); - // pass back to main $zbs->DAL - return $this->DAL()->lazyTable($objType); + // will be objlayer model if set + if ( is_array( $potentialModel ) ) { - } - public function lazyTidy($objType=-1,$obj=false){ + // cycle through each field verify where necessary + foreach ( $potentialModel as $fieldKey => $fieldDetail ) { - // pass back to main $zbs->DAL - return $this->DAL()->lazyTidy($objType,$obj); + // verify fields are not empty + // note. This ignores 'can_be_blank', if is somehow set despite setting not_empty + if ( isset( $fieldDetail['not_empty'] ) && $fieldDetail['not_empty'] ) { - } - public function lazyTidyGeneric($obj=false){ + // needs to ensure field is not empty + if ( empty( $objArr[ $fieldKey ] ) ) { - // pass back to main $zbs->DAL - return $this->DAL()->lazyTidyGeneric($obj); + // pass back the failed field. + $checksFailed[ $fieldKey ] = $fieldDetail; - } - public function space($str='',$pre=false){ + } + } + } // / foreach - // pass back to main $zbs->DAL - return $this->DAL()->space($str,$pre); + } // / if has model - } - public function spaceAnd($str=''){ + } - // pass back to main $zbs->DAL - return $this->DAL()->spaceAnd($str); + // got any fails? + if ( count( $checksFailed ) > 0 ) { + + // can't update, some empties. + + // set reason msg + if ( is_array( $checksFailed ) ) { + foreach ( $checksFailed as $fieldKey => $fieldDetail ) { + $fk = $fieldKey; + if ( isset( $fieldDetail['label'] ) ) { + $fk = $fieldDetail['label']; + } + $msg = __( 'The field:', 'zero-bs-crm' ) . ' "' . $fk . '" ' . __( 'is required', 'zero-bs-crm' ); + $zbs->DAL->addError( 304, $this->objectType, $msg, $fieldKey ); + } + } - } - public function spaceWhere($str=''){ + // return fail + return false; - // pass back to main $zbs->DAL - return $this->DAL()->spaceWhere($str); + } // / fails non blank field verify - } - public function delimiterIf($delimiter,$ifStr=''){ + return true; + } - // pass back to main $zbs->DAL - return $this->DAL()->delimiterIf($delimiter,$ifStr); + /** + * remove any non-db fields from the object + * basically takes array like array('owner'=>1,'fname'=>'x','fullname'=>'x') + * and returns array like array('owner'=>1,'fname'=>'x') + * + * @param array $obj (clean obj) + * + * @return array (db ready arr) + */ + public function db_ready_obj( $obj = false ) { - } - public function stripSlashes($obj=false){ - return zeroBSCRM_stripSlashes( $obj ); - } - public function decodeIfJSON($str=''){ + global $zbs; - // pass back to main $zbs->DAL - return $this->DAL()->decodeIfJSON($str); + // here it has to use the KEY which is without prefix (e.g. status, not zbsc_status) :) + if ( isset( $this->objectModel ) && is_array( $this->objectModel ) ) { - } - public function build_csv($array=array()){ + $ret = array(); + if ( is_array( $obj ) ) { - // pass back to main $zbs->DAL - return $this->DAL()->build_csv($array); + foreach ( $this->objectModel as $fKey => $fObj ) { - } - public function buildWhereStr($whereStr='',$additionalWhere=''){ + if ( isset( $obj[ $fKey ] ) ) { + $ret[ $fKey ] = $obj[ $fKey ]; + } + } - // pass back to main $zbs->DAL - return $this->DAL()->buildWhereStr($whereStr,$additionalWhere); + // gross backward compat - long may this die. + if ( $zbs->db2CompatabilitySupport ) { + $ret['meta'] = $ret; + } + } + } - } - public function buildWheres($wheres=array(),$whereStr='',$params=array(),$andOr='AND',$includeInitialWHERE=true){ + return $ret; + } - // pass back to main $zbs->DAL - return $this->DAL()->buildWheres($wheres,$whereStr,$params,$andOr,$includeInitialWHERE); + /** + * genericified link array of id's with this obj + * Takes current area (e.g. EVENT) as first type, and assigns objlinks EVENT -> $toObjType + * + * @param int $objectID (int of this obj id) + * @param array $objectIDsArr (array of ints (IDs)) - NOTE: can pass 'unset' as str to wipe links + * @param int $toObjectType (int of obj link type) + * + * @return bool of action + */ + public function addUpdateObjectLinks( $objectID = -1, $objectIDsArr = false, $toObjectType = false ) { + if ( $toObjectType > 0 && $objectID > 0 ) { + + // GENERICIFIED OBJ LINKS + if ( isset( $objectIDsArr ) && is_array( $objectIDsArr ) && count( $objectIDsArr ) > 0 ) { + + // replace existing + $this->DAL()->addUpdateObjLinks( + array( + 'objtypefrom' => $this->objectType, + 'objtypeto' => $toObjectType, + 'objfromid' => $objectID, + 'objtoids' => $objectIDsArr, + 'mode' => 'replace', + ) + ); + + return true; + + } elseif ( isset( $objectIDsArr ) && $objectIDsArr == 'unset' ) { + + // wipe previous links + $deleted = $this->DAL()->deleteObjLinks( + array( + 'objtypefrom' => $this->objectType, + 'objtypeto' => $toObjectType, + 'objfromid' => $objectID, + ) + ); // where id = + + return true; - } - public function buildSort($sortByField='',$sortOrder='ASC'){ + } + } - // pass back to main $zbs->DAL - return $this->DAL()->buildSort($sortByField,$sortOrder); + return false; + } - } - public function buildPaging($page=-1,$perPage=-1){ + // =============================================================================== + // =========== DAL2 WRAPPERS ===================================================== + // These are dumb, and pass back directly to parent $zbs->DAL equivilents, centralising them + // ... this is so we can keep $this->lazyTable etc. usage which is simpler than $this->DAL()->lazyTable - // pass back to main $zbs->DAL - return $this->DAL()->buildPaging($page,$perPage); + public function lazyTable( $objType = -1 ) { - } - public function buildWPMetaQueryWhere($metaKey=-1,$metaVal=-1){ + // pass back to main $zbs->DAL + return $this->DAL()->lazyTable( $objType ); + } + public function lazyTidy( $objType = -1, $obj = false ) { - // pass back to main $zbs->DAL - return $this->DAL()->buildWPMetaQueryWhere($metaKey,$metaVal); + // pass back to main $zbs->DAL + return $this->DAL()->lazyTidy( $objType, $obj ); + } + public function lazyTidyGeneric( $obj = false ) { - } - public function getTypeStr($fieldKey=''){ + // pass back to main $zbs->DAL + return $this->DAL()->lazyTidyGeneric( $obj ); + } + public function space( $str = '', $pre = false ) { - // pass back to main $zbs->DAL - return $this->DAL()->getTypeStr($fieldKey); + // pass back to main $zbs->DAL + return $this->DAL()->space( $str, $pre ); + } + public function spaceAnd( $str = '' ) { - } - public function prepare($sql='',$params=array()){ + // pass back to main $zbs->DAL + return $this->DAL()->spaceAnd( $str ); + } + public function spaceWhere( $str = '' ) { - // pass back to main $zbs->DAL - return $this->DAL()->prepare($sql,$params); + // pass back to main $zbs->DAL + return $this->DAL()->spaceWhere( $str ); + } + public function delimiterIf( $delimiter, $ifStr = '' ) { - } - public function catchSQLError($errObj=-1){ + // pass back to main $zbs->DAL + return $this->DAL()->delimiterIf( $delimiter, $ifStr ); + } + public function stripSlashes( $obj = false ) { + return zeroBSCRM_stripSlashes( $obj ); + } + public function decodeIfJSON( $str = '' ) { - // pass back to main $zbs->DAL - return $this->DAL()->catchSQLError($errObj); + // pass back to main $zbs->DAL + return $this->DAL()->decodeIfJSON( $str ); + } + public function build_csv( $array = array() ) { - } - // legacy signpost, this is now overwritten by DAL->contacts->fullname - public function format_fullname($contactArr=array()){ + // pass back to main $zbs->DAL + return $this->DAL()->build_csv( $array ); + } + public function buildWhereStr( $whereStr = '', $additionalWhere = '' ) { - // pass back to main $zbs->DAL - return $this->DAL()->format_fullname($contactArr); + // pass back to main $zbs->DAL + return $this->DAL()->buildWhereStr( $whereStr, $additionalWhere ); + } + public function buildWheres( $wheres = array(), $whereStr = '', $params = array(), $andOr = 'AND', $includeInitialWHERE = true ) { - } - // legacy signpost, this is now overwritten by DAL->[contacts|companies]->format_name_etc - public function format_name_etc($contactArr=array(),$args=array()){ + // pass back to main $zbs->DAL + return $this->DAL()->buildWheres( $wheres, $whereStr, $params, $andOr, $includeInitialWHERE ); + } + public function buildSort( $sortByField = '', $sortOrder = 'ASC' ) { - // pass back to main $zbs->DAL - return $this->DAL()->format_name_etc($contactArr,$args); + // pass back to main $zbs->DAL + return $this->DAL()->buildSort( $sortByField, $sortOrder ); + } + public function buildPaging( $page = -1, $perPage = -1 ) { - } - public function format_address($contactArr=array(),$args=array()){ + // pass back to main $zbs->DAL + return $this->DAL()->buildPaging( $page, $perPage ); + } + public function buildWPMetaQueryWhere( $metaKey = -1, $metaVal = -1 ) { - // pass back to main $zbs->DAL - return $this->DAL()->format_address($contactArr,$args); + // pass back to main $zbs->DAL + return $this->DAL()->buildWPMetaQueryWhere( $metaKey, $metaVal ); + } + public function getTypeStr( $fieldKey = '' ) { - } - public function makeSlug($string, $replace = array(), $delimiter = '-') { + // pass back to main $zbs->DAL + return $this->DAL()->getTypeStr( $fieldKey ); + } + public function prepare( $sql = '', $params = array() ) { - // pass back to main $zbs->DAL - return $this->DAL()->makeSlug($string,$replace,$delimiter); + // pass back to main $zbs->DAL + return $this->DAL()->prepare( $sql, $params ); + } + public function catchSQLError( $errObj = -1 ) { - } - public function makeSlugCleanStr($string='', $delimiter='-'){ + // pass back to main $zbs->DAL + return $this->DAL()->catchSQLError( $errObj ); + } + // legacy signpost, this is now overwritten by DAL->contacts->fullname + public function format_fullname( $contactArr = array() ) { - // pass back to main $zbs->DAL - return $this->DAL()->makeSlugCleanStr($string,$delimiter); + // pass back to main $zbs->DAL + return $this->DAL()->format_fullname( $contactArr ); + } + // legacy signpost, this is now overwritten by DAL->[contacts|companies]->format_name_etc + public function format_name_etc( $contactArr = array(), $args = array() ) { - } - public function ownershipQueryVars($ignoreOwner=false){ + // pass back to main $zbs->DAL + return $this->DAL()->format_name_etc( $contactArr, $args ); + } + public function format_address( $contactArr = array(), $args = array() ) { - // pass back to main $zbs->DAL - return $this->DAL()->ownershipQueryVars($ignoreOwner); + // pass back to main $zbs->DAL + return $this->DAL()->format_address( $contactArr, $args ); + } + public function makeSlug( $string, $replace = array(), $delimiter = '-' ) { - } - public function ownershipSQL($ignoreOwner=false,$table=''){ + // pass back to main $zbs->DAL + return $this->DAL()->makeSlug( $string, $replace, $delimiter ); + } + public function makeSlugCleanStr( $string = '', $delimiter = '-' ) { - // pass back to main $zbs->DAL - return $this->DAL()->ownershipSQL($ignoreOwner,$table); + // pass back to main $zbs->DAL + return $this->DAL()->makeSlugCleanStr( $string, $delimiter ); + } + public function ownershipQueryVars( $ignoreOwner = false ) { - } - public function addUpdateCustomField($args=array()){ + // pass back to main $zbs->DAL + return $this->DAL()->ownershipQueryVars( $ignoreOwner ); + } + public function ownershipSQL( $ignoreOwner = false, $table = '' ) { - // pass back to main $zbs->DAL - return $this->DAL()->addUpdateCustomField($args); + // pass back to main $zbs->DAL + return $this->DAL()->ownershipSQL( $ignoreOwner, $table ); + } + public function addUpdateCustomField( $args = array() ) { - } + // pass back to main $zbs->DAL + return $this->DAL()->addUpdateCustomField( $args ); + } /** * Fixes name clashes between linked objects (e.g. company) and custom fields with the same slug. @@ -1379,6 +1401,6 @@ public function fix_name_clash_if_needed( &$field_name ) { } } - // =========== / DAL2 WRAPPERS =================================================== - // =============================================================================== + // =========== / DAL2 WRAPPERS =================================================== + // =============================================================================== } // / class diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.php index e0f186e2da8b..64a3be0edffd 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.php @@ -1,5 +1,6 @@ -getContacts - - ... in DAL3 these have moved to: - - DAL->contacts->getContacts() - - ... for better organisation. - - This file, then, basically shuffles original DAL2 out into 4 classes: - - DAL, contacts, segments, logs - - As DAL, DAL->contacts, DAL->segments, DAL->logs - - ... it also adds splat/catcher funcs for OLD references e.g. getContacts, - - ... so that they will still function (but log need for replacement) + - Originally this was DAL2 1 x class containting methods like: + - DAL->getContacts + - ... in DAL3 these have moved to: + - DAL->contacts->getContacts() + - ... for better organisation. + - This file, then, basically shuffles original DAL2 out into 4 classes: + - DAL, contacts, segments, logs + - As DAL, DAL->contacts, DAL->segments, DAL->logs + - ... it also adds splat/catcher funcs for OLD references e.g. getContacts, + - ... so that they will still function (but log need for replacement) - ... so it's a kind of chimera DAL2 to bridge the gap between DAL2 + DAL3. - ... should be fine to cut the chimera splats after a while though (or even pre v3.0 proper) + ... so it's a kind of chimera DAL2 to bridge the gap between DAL2 + DAL3. + ... should be fine to cut the chimera splats after a while though (or even pre v3.0 proper) - */ + */ -/* ====================================================== - DB GENERIC/OBJ Helpers (not DAL GET etc.) - ====================================================== */ +/* +====================================================== + DB GENERIC/OBJ Helpers (not DAL GET etc.) + ====================================================== */ - // =============================================================================== - // =========== PERMISSIONS HELPERS ============================================= + // =============================================================================== + // =========== PERMISSIONS HELPERS ============================================= - // in time this'll allow multiple 'sites' per install (E.g. site 1 = epic.zbs.com site 2 = zbs.zbs.com) - // for now, this is hard-coded to 1 - // replaces "zeroBSCRM_installSite" from old DAL - function zeroBSCRM_site(){ + // in time this'll allow multiple 'sites' per install (E.g. site 1 = epic.zbs.com site 2 = zbs.zbs.com) + // for now, this is hard-coded to 1 + // replaces "zeroBSCRM_installSite" from old DAL +function zeroBSCRM_site() { - return 1; - - } - // in time this'll allow multiple 'team' per site (E.g. branch1,branch2 etc.) - // for now, this is hard-coded to 1 - // replaces "zeroBSCRM_installTeam" from old DAL - function zeroBSCRM_team(){ - - return 1; - - } - // active user id - helper func - // replaces "zeroBSCRM_currentUserID" from old DAL - // can alternatively user $zbs->user() - function zeroBSCRM_user(){ + return 1; +} + // in time this'll allow multiple 'team' per site (E.g. branch1,branch2 etc.) + // for now, this is hard-coded to 1 + // replaces "zeroBSCRM_installTeam" from old DAL +function zeroBSCRM_team() { - return get_current_user_id(); + return 1; +} + // active user id - helper func + // replaces "zeroBSCRM_currentUserID" from old DAL + // can alternatively user $zbs->user() +function zeroBSCRM_user() { - } + return get_current_user_id(); +} - // =========== / PERMISSIONS HELPERS =========================================== - // =============================================================================== + // =========== / PERMISSIONS HELPERS =========================================== + // =============================================================================== - // =============================================================================== - // =========== TYPES ============================================================ + // =============================================================================== + // =========== TYPES ============================================================ define( 'ZBS_TYPE_CONTACT', 1 ); define( 'ZBS_TYPE_COMPANY', 2 ); @@ -87,37 +86,34 @@ function zeroBSCRM_user(){ define( 'ZBS_TYPE_QUOTETEMPLATE', 12 ); define( 'ZBS_TYPE_ADDRESS', 13 ); // this is a precursor to v4 where we likely need to split out addresses from current in-object model (included here as custom fields now managed as if obj) - // =========== / TYPES ========================================================= - // =============================================================================== - - -/* ====================================================== - / DB GENERIC/OBJ Helpers (not DAL GET etc.) - ====================================================== */ - - + // =========== / TYPES ========================================================= + // =============================================================================== +/* +====================================================== + / DB GENERIC/OBJ Helpers (not DAL GET etc.) + ====================================================== */ /** -* zbsDAL is the Data Access Layer for ZBS v2.5+ -* -* zbsDAL provides expanded CRUD actions to the -* Jetpack CRM generally, and will be initiated globally -* like the WordPress $wpdb. -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * zbsDAL is the Data Access Layer for ZBS v2.5+ + * + * zbsDAL provides expanded CRUD actions to the + * Jetpack CRM generally, and will be initiated globally + * like the WordPress $wpdb. + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL { - public $version = 3.0; + public $version = 3.0; - /* - * A general key-value pair store - */ - private $cache = array(); + /* + * A general key-value pair store + */ + private $cache = array(); /** * This is a temporary fix for issue #3504, until we don't change how we load settings this should help to avoid slowing down websites. @@ -200,66 +196,64 @@ private static function mitigation_cache_for_issue_3504_all_settings() { return static::$mitigation_cache_for_issue_3504['settings']; } - // =============================================================================== - // =========== SUB DAL LAYERS ================================================== - // These hold sub-objects, e.g. contact - public $contacts = false; - public $segments = false; - public $companies = false; - public $quotes = false; - public $invoices = false; - public $transactions = false; - public $forms = false; - public $events = false; + // =============================================================================== + // =========== SUB DAL LAYERS ================================================== + // These hold sub-objects, e.g. contact + public $contacts = false; + public $segments = false; + public $companies = false; + public $quotes = false; + public $invoices = false; + public $transactions = false; + public $forms = false; + public $events = false; public $eventreminders = false; // phpcs:ignore Squiz.Commenting.VariableComment.Missing - public $logs = false; - public $lineitems = false; - public $quotetemplates = false; - public $addresses = false; - - - // =========== / SUB DAL LAYERS ================================================ - // =============================================================================== - - - // =============================================================================== - // =========== OBJECT TYPE & GLOBAL DEFINITIONS ============================== - - private $typesByID = array( - - ZBS_TYPE_CONTACT => 'contact', - ZBS_TYPE_COMPANY => 'company', - ZBS_TYPE_QUOTE => 'quote', - ZBS_TYPE_INVOICE => 'invoice', - ZBS_TYPE_TRANSACTION => 'transaction', - ZBS_TYPE_TASK => 'event', - ZBS_TYPE_FORM => 'form', - ZBS_TYPE_SEGMENT => 'segment', - ZBS_TYPE_LOG => 'log', - ZBS_TYPE_LINEITEM => 'lineitem', - ZBS_TYPE_TASK_REMINDER => 'eventreminder', - ZBS_TYPE_QUOTETEMPLATE => 'quotetemplate', - ZBS_TYPE_ADDRESS => 'address' - - ); - - // retrieve via DAL->oldCPT(1) - private $typeCPT = array( - - ZBS_TYPE_CONTACT => 'zerobs_customer', - ZBS_TYPE_COMPANY => 'zerobs_company', - ZBS_TYPE_QUOTE => 'zerobs_quote', - ZBS_TYPE_INVOICE => 'zerobs_invoice', - ZBS_TYPE_TRANSACTION => 'zerobs_transaction', - ZBS_TYPE_TASK => 'zerobs_event', - ZBS_TYPE_FORM => 'zerobs_form', - // these never existed: - //ZBS_TYPE_SEGMENT => 'zerobs_segment', - //ZBS_TYPE_LOG => 'zerobs_log', - //ZBS_TYPE_LINEITEM => 'lineitem' - //ZBS_TYPE_TASK_REMINDER => 'eventreminder' - ZBS_TYPE_QUOTETEMPLATE => 'zerobs_quo_template', - ); + public $logs = false; + public $lineitems = false; + public $quotetemplates = false; + public $addresses = false; + + // =========== / SUB DAL LAYERS ================================================ + // =============================================================================== + + // =============================================================================== + // =========== OBJECT TYPE & GLOBAL DEFINITIONS ============================== + + private $typesByID = array( + + ZBS_TYPE_CONTACT => 'contact', + ZBS_TYPE_COMPANY => 'company', + ZBS_TYPE_QUOTE => 'quote', + ZBS_TYPE_INVOICE => 'invoice', + ZBS_TYPE_TRANSACTION => 'transaction', + ZBS_TYPE_TASK => 'event', + ZBS_TYPE_FORM => 'form', + ZBS_TYPE_SEGMENT => 'segment', + ZBS_TYPE_LOG => 'log', + ZBS_TYPE_LINEITEM => 'lineitem', + ZBS_TYPE_TASK_REMINDER => 'eventreminder', + ZBS_TYPE_QUOTETEMPLATE => 'quotetemplate', + ZBS_TYPE_ADDRESS => 'address', + + ); + + // retrieve via DAL->oldCPT(1) + private $typeCPT = array( + + ZBS_TYPE_CONTACT => 'zerobs_customer', + ZBS_TYPE_COMPANY => 'zerobs_company', + ZBS_TYPE_QUOTE => 'zerobs_quote', + ZBS_TYPE_INVOICE => 'zerobs_invoice', + ZBS_TYPE_TRANSACTION => 'zerobs_transaction', + ZBS_TYPE_TASK => 'zerobs_event', + ZBS_TYPE_FORM => 'zerobs_form', + // these never existed: + // ZBS_TYPE_SEGMENT => 'zerobs_segment', + // ZBS_TYPE_LOG => 'zerobs_log', + // ZBS_TYPE_LINEITEM => 'lineitem' + // ZBS_TYPE_TASK_REMINDER => 'eventreminder' + ZBS_TYPE_QUOTETEMPLATE => 'zerobs_quo_template', + ); /** * Retrieve via DAL->typeStr(1). @@ -272,7 +266,7 @@ private static function mitigation_cache_for_issue_3504_all_settings() { ZBS_TYPE_QUOTE => array( 'Quote', 'Quotes' ), ZBS_TYPE_INVOICE => array( 'Invoice', 'Invoices' ), ZBS_TYPE_TRANSACTION => array( 'Transaction', 'Transactions' ), - ZBS_TYPE_TASK => array( 'Task', 'Tasks' ), + ZBS_TYPE_TASK => array( 'Task', 'Tasks' ), ZBS_TYPE_FORM => array( 'Form', 'Forms' ), ZBS_TYPE_SEGMENT => array( 'Segment', 'Segments' ), ZBS_TYPE_LOG => array( 'Log', 'Logs' ), @@ -282,226 +276,245 @@ private static function mitigation_cache_for_issue_3504_all_settings() { ZBS_TYPE_ADDRESS => array( 'Address', 'Addresses' ), ); - // List View refs - private $listViewRefs = array( - - // each of these is a slug for $zbs->slugs e.g. $zbs->slugs['managecontacts'] - ZBS_TYPE_CONTACT => 'managecontacts', - ZBS_TYPE_COMPANY => 'managecompanies', - ZBS_TYPE_QUOTE => 'managequotes', - ZBS_TYPE_INVOICE => 'manageinvoices', - ZBS_TYPE_TRANSACTION => 'managetransactions', - ZBS_TYPE_TASK => 'manage-tasks', - ZBS_TYPE_FORM => 'manageformscrm', - ZBS_TYPE_SEGMENT => 'segments', - //no list page ZBS_TYPE_LOG => 'managecontacts', - //no list page ZBS_TYPE_LINEITEM => 'managecontacts', - //no list page ZBS_TYPE_TASK_REMINDER => 'managecontacts', - ZBS_TYPE_QUOTETEMPLATE => 'quote-templates' - ); - - - - // field obj models - // these match the $globals in fields.php - bit of a legacy chunk tbh, but used throughout - private $fieldModelsByID = array( - - ZBS_TYPE_CONTACT => 'zbsCustomerFields', - ZBS_TYPE_COMPANY => 'zbsCompanyFields', - ZBS_TYPE_QUOTE => 'zbsCustomerQuoteFields', - ZBS_TYPE_INVOICE => 'zbsCustomerInvoiceFields', - ZBS_TYPE_TRANSACTION => 'zbsTransactionFields', - //ZBS_TYPE_TASK => 'zbsFormFields', - ZBS_TYPE_FORM => 'zbsFormFields', - ZBS_TYPE_ADDRESS => 'zbsAddressFields' - - ); - - // legacy support. - private $oldTaxonomies = array( - - 'zerobscrm_customertag' => ZBS_TYPE_CONTACT, - 'zerobscrm_companytag' => ZBS_TYPE_COMPANY, - 'zerobscrm_transactiontag' => ZBS_TYPE_TRANSACTION, - 'zerobscrm_logtag' => ZBS_TYPE_LOG, - - ); - - - // this is a shorthand for grabbing all addr fields - private $field_list_address = array( - - 'zbsc_addr1','zbsc_addr2','zbsc_city','zbsc_postcode','zbsc_county','zbsc_country' - - ); - private $field_list_address2 = array( - - 'zbsc_secaddr1','zbsc_secaddr2','zbsc_seccity','zbsc_secpostcode','zbsc_seccounty','zbsc_seccountry' - - ); - private $field_list_address_full = array( - - 'zbsc_addr1','zbsc_addr2','zbsc_city','zbsc_postcode','zbsc_county','zbsc_country', - 'zbsc_secaddr1','zbsc_secaddr2','zbsc_seccity','zbsc_secpostcode','zbsc_seccounty','zbsc_seccountry' - - ); - - // this stores any insert errors - private $errorStack = array(); - - - /** - * Prefix for origin strings which are domains (should mean querying easier later) - * Used throughout to specify domain - */ - private $prefix_domain = 'd:'; - - // =========== / OBJECT TYPE & GLOBAL DEFINITIONS ============================= - // =============================================================================== - - - + // List View refs + private $listViewRefs = array( + + // each of these is a slug for $zbs->slugs e.g. $zbs->slugs['managecontacts'] + ZBS_TYPE_CONTACT => 'managecontacts', + ZBS_TYPE_COMPANY => 'managecompanies', + ZBS_TYPE_QUOTE => 'managequotes', + ZBS_TYPE_INVOICE => 'manageinvoices', + ZBS_TYPE_TRANSACTION => 'managetransactions', + ZBS_TYPE_TASK => 'manage-tasks', + ZBS_TYPE_FORM => 'manageformscrm', + ZBS_TYPE_SEGMENT => 'segments', + // no list page ZBS_TYPE_LOG => 'managecontacts', + // no list page ZBS_TYPE_LINEITEM => 'managecontacts', + // no list page ZBS_TYPE_TASK_REMINDER => 'managecontacts', + ZBS_TYPE_QUOTETEMPLATE => 'quote-templates', + ); - // =============================================================================== - // =========== INIT ============================================================= - function __construct($args=array()) { + // field obj models + // these match the $globals in fields.php - bit of a legacy chunk tbh, but used throughout + private $fieldModelsByID = array( - // init sub-layers: - $this->contacts = new zbsDAL_contacts; - $this->segments = new zbsDAL_segments; + ZBS_TYPE_CONTACT => 'zbsCustomerFields', + ZBS_TYPE_COMPANY => 'zbsCompanyFields', + ZBS_TYPE_QUOTE => 'zbsCustomerQuoteFields', + ZBS_TYPE_INVOICE => 'zbsCustomerInvoiceFields', + ZBS_TYPE_TRANSACTION => 'zbsTransactionFields', + // ZBS_TYPE_TASK => 'zbsFormFields', + ZBS_TYPE_FORM => 'zbsFormFields', + ZBS_TYPE_ADDRESS => 'zbsAddressFields', - $this->companies = new zbsDAL_companies; - $this->quotes = new zbsDAL_quotes; - $this->invoices = new zbsDAL_invoices; - $this->transactions = new zbsDAL_transactions; - $this->forms = new zbsDAL_forms; - $this->events = new zbsDAL_events; - $this->eventreminders = new zbsDAL_eventreminders; - $this->logs = new zbsDAL_logs; - $this->lineitems = new zbsDAL_lineitems; - $this->quotetemplates = new zbsDAL_quotetemplates; - // Not yet implemented: - // $this->addresses = new zbsDAL_addresses; - - // any post-settings-loaded actions - add_action( 'after_zerobscrm_settings_preinit', [ $this, 'postSettingsInit' ] ); + ); - } - // =========== / INIT =========================================================== - // =============================================================================== + // legacy support. + private $oldTaxonomies = array( + 'zerobscrm_customertag' => ZBS_TYPE_CONTACT, + 'zerobscrm_companytag' => ZBS_TYPE_COMPANY, + 'zerobscrm_transactiontag' => ZBS_TYPE_TRANSACTION, + 'zerobscrm_logtag' => ZBS_TYPE_LOG, - /** - * Corrects label for 'Company' (could be Organisation) after the settings have loaded. - * Clunky workaround for now - */ - public function postSettingsInit(){ + ); - // Correct any labels - $this->typeNames[ZBS_TYPE_COMPANY] = array(jpcrm_label_company(),jpcrm_label_company(true)); + // this is a shorthand for grabbing all addr fields + private $field_list_address = array( - } + 'zbsc_addr1', + 'zbsc_addr2', + 'zbsc_city', + 'zbsc_postcode', + 'zbsc_county', + 'zbsc_country', + ); + private $field_list_address2 = array( - // =============================================================================== - // =========== HELPER/GET FUNCS ================================================= + 'zbsc_secaddr1', + 'zbsc_secaddr2', + 'zbsc_seccity', + 'zbsc_secpostcode', + 'zbsc_seccounty', + 'zbsc_seccountry', - public function field_list_address(){ return $this->field_list_address; } - public function field_list_address2(){ return $this->field_list_address2; } - public function field_list_address_full(){ return $this->field_list_address_full; } - - // returns object types indexed by their global (e.g. ZBS_TYPE_CONTACT = 1) - public function get_object_types_by_index(){ + ); + private $field_list_address_full = array( + + 'zbsc_addr1', + 'zbsc_addr2', + 'zbsc_city', + 'zbsc_postcode', + 'zbsc_county', + 'zbsc_country', + 'zbsc_secaddr1', + 'zbsc_secaddr2', + 'zbsc_seccity', + 'zbsc_secpostcode', + 'zbsc_seccounty', + 'zbsc_seccountry', - return $this->typesByID; + ); - } + // this stores any insert errors + private $errorStack = array(); - // returns object types indexed by their key (e.g. 'contact' => ZBS_TYPE_CONTACT = 1) - public function getObjectTypesByKey(){ + /** + * Prefix for origin strings which are domains (should mean querying easier later) + * Used throughout to specify domain + */ + private $prefix_domain = 'd:'; + + // =========== / OBJECT TYPE & GLOBAL DEFINITIONS ============================= + // =============================================================================== + + // =============================================================================== + // =========== INIT ============================================================= + function __construct( $args = array() ) { + + // init sub-layers: + $this->contacts = new zbsDAL_contacts(); + $this->segments = new zbsDAL_segments(); + + $this->companies = new zbsDAL_companies(); + $this->quotes = new zbsDAL_quotes(); + $this->invoices = new zbsDAL_invoices(); + $this->transactions = new zbsDAL_transactions(); + $this->forms = new zbsDAL_forms(); + $this->events = new zbsDAL_events(); + $this->eventreminders = new zbsDAL_eventreminders(); + $this->logs = new zbsDAL_logs(); + $this->lineitems = new zbsDAL_lineitems(); + $this->quotetemplates = new zbsDAL_quotetemplates(); + // Not yet implemented: + // $this->addresses = new zbsDAL_addresses; + + // any post-settings-loaded actions + add_action( 'after_zerobscrm_settings_preinit', array( $this, 'postSettingsInit' ) ); + } + // =========== / INIT =========================================================== + // =============================================================================== - return array_flip($this->typesByID); + /** + * Corrects label for 'Company' (could be Organisation) after the settings have loaded. + * Clunky workaround for now + */ + public function postSettingsInit() { - } + // Correct any labels + $this->typeNames[ ZBS_TYPE_COMPANY ] = array( jpcrm_label_company(), jpcrm_label_company( true ) ); + } - public function getCPTObjectTypesByKey(){ + // =============================================================================== + // =========== HELPER/GET FUNCS ================================================= - return array_flip($this->typeCPT); + public function field_list_address() { + return $this->field_list_address; } + public function field_list_address2() { + return $this->field_list_address2; } + public function field_list_address_full() { + return $this->field_list_address_full; } - } + // returns object types indexed by their global (e.g. ZBS_TYPE_CONTACT = 1) + public function get_object_types_by_index() { - // returns $zbs->DAL->contacts by '1' - // for now brutal switch, avoid using anywhere but internally, use proper refs elsewhere - // ... avoid use where not essential as does not produce highly readable code. - public function getObjectLayerByType($objTypeID=-1){ + return $this->typesByID; + } - switch ($objTypeID){ - case ZBS_TYPE_CONTACT: - return $this->contacts; break; - case ZBS_TYPE_COMPANY: - return $this->companies; break; - case ZBS_TYPE_QUOTE: - return $this->quotes; break; - case ZBS_TYPE_INVOICE: - return $this->invoices; break; - case ZBS_TYPE_TRANSACTION: - return $this->transactions; break; - case ZBS_TYPE_FORM: - return $this->forms; break; - case ZBS_TYPE_TASK: - return $this->events; break; - case ZBS_TYPE_TASK_REMINDER: - return $this->eventreminders; break; - case ZBS_TYPE_LOG: - return $this->logs; break; - case ZBS_TYPE_LINEITEM: - return $this->lineitems; break; - case ZBS_TYPE_QUOTETEMPLATE: - return $this->quotetemplates; break; - // case ZBS_TYPE_ADDRESS: - // return $this->addresses; break; - } + // returns object types indexed by their key (e.g. 'contact' => ZBS_TYPE_CONTACT = 1) + public function getObjectTypesByKey() { - return false; + return array_flip( $this->typesByID ); + } - } + public function getCPTObjectTypesByKey() { - /** - * Returns $zbsCustomerFields global from object_type_id - * designed as legacy support until we can refactor away from globals (gh-253) - * - * @param CRM_TYPE int object_type_id - object type ID\ - * - * @return bool|array - object type field global array, or false - */ - public function get_object_field_global( $object_type_id = -1 ){ + return array_flip( $this->typeCPT ); + } - // attempt to retrieve var - $global_var_name = $this->objFieldVarName( $object_type_id ); + // returns $zbs->DAL->contacts by '1' + // for now brutal switch, avoid using anywhere but internally, use proper refs elsewhere + // ... avoid use where not essential as does not produce highly readable code. + public function getObjectLayerByType( $objTypeID = -1 ) { - if ( $global_var_name !== -1){ + switch ( $objTypeID ) { + case ZBS_TYPE_CONTACT: + return $this->contacts; + break; + case ZBS_TYPE_COMPANY: + return $this->companies; + break; + case ZBS_TYPE_QUOTE: + return $this->quotes; + break; + case ZBS_TYPE_INVOICE: + return $this->invoices; + break; + case ZBS_TYPE_TRANSACTION: + return $this->transactions; + break; + case ZBS_TYPE_FORM: + return $this->forms; + break; + case ZBS_TYPE_TASK: + return $this->events; + break; + case ZBS_TYPE_TASK_REMINDER: + return $this->eventreminders; + break; + case ZBS_TYPE_LOG: + return $this->logs; + break; + case ZBS_TYPE_LINEITEM: + return $this->lineitems; + break; + case ZBS_TYPE_QUOTETEMPLATE: + return $this->quotetemplates; + break; + // case ZBS_TYPE_ADDRESS: + // return $this->addresses; break; + } - return isset( $GLOBALS[ $global_var_name ] ) ? $GLOBALS[ $global_var_name ] : null; + return false; + } - } + /** + * Returns $zbsCustomerFields global from object_type_id + * designed as legacy support until we can refactor away from globals (gh-253) + * + * @param CRM_TYPE int object_type_id - object type ID\ + * + * @return bool|array - object type field global array, or false + */ + public function get_object_field_global( $object_type_id = -1 ) { - return false; + // attempt to retrieve var + $global_var_name = $this->objFieldVarName( $object_type_id ); - } + if ( $global_var_name !== -1 ) { + return isset( $GLOBALS[ $global_var_name ] ) ? $GLOBALS[ $global_var_name ] : null; + } - public function isValidObjTypeID($objTypeIn=false){ + return false; + } - // if it's not an int type, cast it...? - if (!is_int($objTypeIn)) $objTypeIn = (int)$objTypeIn; + public function isValidObjTypeID( $objTypeIn = false ) { - // if bigger than 0 and in our arr as a key, basic check - if ($objTypeIn > 0 && isset($this->typesByID[$objTypeIn])) return true; + // if it's not an int type, cast it...? + if ( ! is_int( $objTypeIn ) ) { + $objTypeIn = (int) $objTypeIn; + } - return false; + // if bigger than 0 and in our arr as a key, basic check + if ( $objTypeIn > 0 && isset( $this->typesByID[ $objTypeIn ] ) ) { + return true; + } - } + return false; + } /** * Check if a given status is valid for the given object @@ -531,148 +544,153 @@ public function is_valid_obj_status( $obj_type_id, $obj_status ) { return in_array( $obj_status, $valid_statuses, true ); } - // takes in an obj type str (e.g. 'contact') and returns DEFINED KEY ID = 1 - public function objTypeID($objTypeStr=''){ - - // catch some legacy translations - if ($objTypeStr == 'customer') $objTypeStr = 'contact'; - - $byStr = $this->getObjectTypesByKey(); - if (isset($byStr[$objTypeStr])) return $byStr[$objTypeStr]; - - // if not, fall back to old obj cpt types - $byStr = $this->getCPTObjectTypesByKey(); - if (isset($byStr[$objTypeStr])) return $byStr[$objTypeStr]; - - return -1; + // takes in an obj type str (e.g. 'contact') and returns DEFINED KEY ID = 1 + public function objTypeID( $objTypeStr = '' ) { - } - - // takes in an obj type int (e.g. 1) and returns key (e.g. 'contact') - public function objTypeKey($objTypeID=-1){ - - if (isset($this->typesByID[$objTypeID])) return $this->typesByID[$objTypeID]; - - return -1; - - } - - // takes in an obj type int (e.g. 1) and returns field global var name (e.g. 'zbsCustomerFields') - public function objFieldVarName($objTypeID=-1){ + // catch some legacy translations + if ( $objTypeStr == 'customer' ) { + $objTypeStr = 'contact'; + } - if (isset($this->fieldModelsByID[$objTypeID])) return $this->fieldModelsByID[$objTypeID]; + $byStr = $this->getObjectTypesByKey(); + if ( isset( $byStr[ $objTypeStr ] ) ) { + return $byStr[ $objTypeStr ]; + } - return -1; + // if not, fall back to old obj cpt types + $byStr = $this->getCPTObjectTypesByKey(); + if ( isset( $byStr[ $objTypeStr ] ) ) { + return $byStr[ $objTypeStr ]; + } - } + return -1; + } - // takes in an obj type (e.g. 1) and returns obj model for that type (as per sub layer) - // uses getObjectLayerByType to keep generic. Use only in fairly high level generic funcs. - public function objModel($objTypeID=-1){ + // takes in an obj type int (e.g. 1) and returns key (e.g. 'contact') + public function objTypeKey( $objTypeID = -1 ) { - if ($objTypeID > 0){ + if ( isset( $this->typesByID[ $objTypeID ] ) ) { + return $this->typesByID[ $objTypeID ]; + } - $objLayer = $this->getObjectLayerByType($objTypeID); + return -1; + } - // if set, $objLayer will effectively be $zbs->DAL->contacts obj - if (method_exists($objLayer,'objModel')){ + // takes in an obj type int (e.g. 1) and returns field global var name (e.g. 'zbsCustomerFields') + public function objFieldVarName( $objTypeID = -1 ) { - // all good - return $objLayer->objModel(); - } + if ( isset( $this->fieldModelsByID[ $objTypeID ] ) ) { + return $this->fieldModelsByID[ $objTypeID ]; + } - } + return -1; + } - return false; - - } + // takes in an obj type (e.g. 1) and returns obj model for that type (as per sub layer) + // uses getObjectLayerByType to keep generic. Use only in fairly high level generic funcs. + public function objModel( $objTypeID = -1 ) { - // takes in an old taxonomy str (e.g. zerobscrm_customertag) and returns new obj key (e.g. 1) - public function cptTaxonomyToObjID($taxonomyStr=-1){ + if ( $objTypeID > 0 ) { - if (isset($this->oldTaxonomies[$taxonomyStr])) return $this->oldTaxonomies[$taxonomyStr]; + $objLayer = $this->getObjectLayerByType( $objTypeID ); - return -1; + // if set, $objLayer will effectively be $zbs->DAL->contacts obj + if ( method_exists( $objLayer, 'objModel' ) ) { - } + // all good + return $objLayer->objModel(); + } + } - // takes in an obj ID and gives back the list view slug - public function listViewSlugFromObjID($objTypeID=-1){ + return false; + } - global $zbs; + // takes in an old taxonomy str (e.g. zerobscrm_customertag) and returns new obj key (e.g. 1) + public function cptTaxonomyToObjID( $taxonomyStr = -1 ) { - if (isset($this->listViewRefs[$objTypeID]) && isset($zbs->slugs[$this->listViewRefs[$objTypeID]])) return $zbs->slugs[$this->listViewRefs[$objTypeID]]; + if ( isset( $this->oldTaxonomies[ $taxonomyStr ] ) ) { + return $this->oldTaxonomies[ $taxonomyStr ]; + } - return ''; + return -1; + } - } + // takes in an obj ID and gives back the list view slug + public function listViewSlugFromObjID( $objTypeID = -1 ) { - // retrieves single/plural 'str' for obj type id (e.g. 1 = Contact/Contacts) - public function typeStr($typeInt=-1,$plural=false){ + global $zbs; - $typeInt = (int)$typeInt; - if ($typeInt > 0){ + if ( isset( $this->listViewRefs[ $objTypeID ] ) && isset( $zbs->slugs[ $this->listViewRefs[ $objTypeID ] ] ) ) { + return $zbs->slugs[ $this->listViewRefs[ $objTypeID ] ]; + } - if (isset($this->typeNames[$typeInt])){ + return ''; + } - // plural - if ($plural) return __($this->typeNames[$typeInt][1],'zero-bs-crm'); - // single - return __($this->typeNames[$typeInt][0],'zero-bs-crm'); + // retrieves single/plural 'str' for obj type id (e.g. 1 = Contact/Contacts) + public function typeStr( $typeInt = -1, $plural = false ) { - } + $typeInt = (int) $typeInt; + if ( $typeInt > 0 ) { - } - return ''; - } + if ( isset( $this->typeNames[ $typeInt ] ) ) { - // retrieves old CPT for that type - public function typeCPT($typeInt=-1){ + // plural + if ( $plural ) { + return __( $this->typeNames[ $typeInt ][1], 'zero-bs-crm' ); + } + // single + return __( $this->typeNames[ $typeInt ][0], 'zero-bs-crm' ); - $typeInt = (int)$typeInt; - if ($typeInt > 0){ + } + } + return ''; + } - if (isset($this->typeCPT[$typeInt])) return $this->typeCPT[$typeInt]; - } - return false; - } + // retrieves old CPT for that type + public function typeCPT( $typeInt = -1 ) { + $typeInt = (int) $typeInt; + if ( $typeInt > 0 ) { - /* - * This function provides a general list of field slugs which should - * be hidden on front end aspects (e.g. Portal, WooSync->WooCommerce My Account) - * - * @param int $obj_type_int - optionally specifies whether 'globally' non inclusive, or 'globally+objmodel specific' - */ - public function fields_to_hide_on_frontend( $obj_type_int = false ){ + if ( isset( $this->typeCPT[ $typeInt ] ) ) { + return $this->typeCPT[ $typeInt ]; + } + } + return false; + } - // Globals - $fields_to_hide_on_frontend = array( 'status', 'email', 'zbs_site', 'zbs_team', 'zbs_owner' ); + /* + * This function provides a general list of field slugs which should + * be hidden on front end aspects (e.g. Portal, WooSync->WooCommerce My Account) + * + * @param int $obj_type_int - optionally specifies whether 'globally' non inclusive, or 'globally+objmodel specific' + */ + public function fields_to_hide_on_frontend( $obj_type_int = false ) { - // Object type specific - if ( $this->isValidObjTypeID( $obj_type_int ) ){ + // Globals + $fields_to_hide_on_frontend = array( 'status', 'email', 'zbs_site', 'zbs_team', 'zbs_owner' ); - $obj_model = $this->objModel( $obj_type_int ); + // Object type specific + if ( $this->isValidObjTypeID( $obj_type_int ) ) { - foreach ( $obj_model as $field_key => $field_array ){ + $obj_model = $this->objModel( $obj_type_int ); - if ( is_array( $field_array ) && isset( $field_array['do_not_show_on_portal'] ) && $field_array['do_not_show_on_portal'] ){ + foreach ( $obj_model as $field_key => $field_array ) { - if ( !in_array( $field_key, $fields_to_hide_on_frontend ) ){ - - $fields_to_hide_on_frontend[] = $field_key; - - } + if ( is_array( $field_array ) && isset( $field_array['do_not_show_on_portal'] ) && $field_array['do_not_show_on_portal'] ) { - } + if ( ! in_array( $field_key, $fields_to_hide_on_frontend ) ) { - } + $fields_to_hide_on_frontend[] = $field_key; - } - - return $fields_to_hide_on_frontend; + } + } + } + } - } + return $fields_to_hide_on_frontend; + } /** * Returns a count of objects of a type which are associated with an assignee (eg. company or contact) @@ -726,1011 +744,1215 @@ public function specific_obj_type_count_for_assignee( $assignee_id, $obj_type_id // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - // =========== / HELPER/GET FUNCS ================================================ - // =============================================================================== - - - + // =========== / HELPER/GET FUNCS ================================================ + // =============================================================================== - // =============================================================================== - // =========== OWNERSHIP HELPERS =============================================== + // =============================================================================== + // =========== OWNERSHIP HELPERS =============================================== // This func is a side-switch alternative to now-removed zeroBS_checkOwner - public function checkObjectOwner($args=array()){ + public function checkObjectOwner( $args = array() ) { - #} =========== LOAD ARGS ============== - $defaultArgs = array( + #} =========== LOAD ARGS ============== + $defaultArgs = array( - 'objID' => -1, - 'objTypeID' => -1, + 'objID' => -1, + 'objTypeID' => -1, - // id to compare to - 'potentialOwnerID' => -1, + // id to compare to + 'potentialOwnerID' => -1, - // if not owned, return true? - 'allowNoOwnerAccess' => -1 + // if not owned, return true? + 'allowNoOwnerAccess' => -1, - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS =============) + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS =============) - if ($objID !== -1 && $objTypeID > 0){ + if ( $objID !== -1 && $objTypeID > 0 ) { - $ownerID = $this->getObjectOwner(array( - 'objID' => $objID, - 'objTypeID' => $objTypeID - )); + $ownerID = $this->getObjectOwner( + array( + 'objID' => $objID, + 'objTypeID' => $objTypeID, + ) + ); - if (isset($ownerID) && $ownerID == $potentialOwnerID) - return true; - // no owner owns this! + if ( isset( $ownerID ) && $ownerID == $potentialOwnerID ) { + return true; + } + // no owner owns this! elseif ( $allowNoOwnerAccess && $potentialOwner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase return true; } - } - - return false; - - } - - // This func is a side-switch alternative to zeroBS_getOwner - public function getObjectOwner($args=array()){ - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - 'objID' => -1, - 'objTypeID' => -1 - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS =============) - - if ($objID !== -1 && $objTypeID > 0){ - - return $this->getFieldByID(array( - 'id' => $objID, - 'objtype' => $objTypeID, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); - - } - - return false; - - } - - // This func is a side-switch alternative to zeroBS_setOwner - public function setObjectOwner($args=array()){ - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - 'objID' => -1, - 'objTypeID' => -1, + } - 'ownerID' => -1 + return false; + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS =============) + // This func is a side-switch alternative to zeroBS_getOwner + public function getObjectOwner( $args = array() ) { - if ($objID !== -1 && $objTypeID > 0){ + #} =========== LOAD ARGS ============== + $defaultArgs = array( - return $this->setFieldByID(array( + 'objID' => -1, + 'objTypeID' => -1, - 'objID' => $objID, - 'objTypeID' => $objTypeID, + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS =============) - 'colname' => 'zbs_owner', - 'coldatatype' => '%d', // %d/s - 'newValue' => $ownerID + if ( $objID !== -1 && $objTypeID > 0 ) { - )); + return $this->getFieldByID( + array( + 'id' => $objID, + 'objtype' => $objTypeID, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); - } + } - return false; + return false; + } - } + // This func is a side-switch alternative to zeroBS_setOwner + public function setObjectOwner( $args = array() ) { - // this is used to get specific user's settings via userSetting - private $userSettingPrefix = 'usrset_'; // completes via usrset_*ID*_key + #} =========== LOAD ARGS ============== + $defaultArgs = array( - /* old way of doing it: (we now use zbs_owner :)) - private function getUserSettingPrefix($userID=-1){ + 'objID' => -1, + 'objTypeID' => -1, - // completes usrset_*ID*_key - return $this->userSettingPrefix.$userID.'_'; - } */ + 'ownerID' => -1, - // Note: Following MUST be used together. + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS =============) - // this makes query vars (as appropriate) team + site (and owner if $ignoreOwner not false) - public function ownershipQueryVars($ignoreOwner=false){ + if ( $objID !== -1 && $objTypeID > 0 ) { - $queryVars = array(); + return $this->setFieldByID( + array( - // add site - // FOR V3.0 SITE + TEAM NOT YET USED, (BUT THIS'll WORK) - //$queryVars[] = zeroBSCRM_site(); + 'objID' => $objID, + 'objTypeID' => $objTypeID, - // add team - // FOR V3.0 SITE + TEAM NOT YET USED, (BUT THIS'll WORK) - //$queryVars[] = zeroBSCRM_team(); + 'colname' => 'zbs_owner', + 'coldatatype' => '%d', // %d/s + 'newValue' => $ownerID, - // add owner - if (!$ignoreOwner) $queryVars[] = zeroBSCRM_user(); + ) + ); - return $queryVars; - - } - // this makes query str (as appropriate) team + site (and owner if $ignoreOwner not false) - // $table ONLY needed when is a LEFT JOIN or similar. - public function ownershipSQL($ignoreOwner=false,$table=''){ + } - // build - $q = ''; $tableStr = ''; if (!empty($table)) $tableStr = $table.'.'; + return false; + } - // add site - // FOR V3.0 SITE + TEAM NOT YET USED, (BUT THIS'll WORK) - //$q = $this->spaceAnd($q).$tableStr.'zbs_site = %d'; + // this is used to get specific user's settings via userSetting + private $userSettingPrefix = 'usrset_'; // completes via usrset_*ID*_key - // add team - // FOR V3.0 SITE + TEAM NOT YET USED, (BUT THIS'll WORK) - //$q = $this->spaceAnd($q).$tableStr.'zbs_team = %d'; + /* + old way of doing it: (we now use zbs_owner :)) + private function getUserSettingPrefix($userID=-1){ - // add owner - if (!$ignoreOwner) $q = $this->spaceAnd($q).$tableStr.'zbs_owner = %d'; + // completes usrset_*ID*_key + return $this->userSettingPrefix.$userID.'_'; + } */ - return $q; - - } + // Note: Following MUST be used together. + // this makes query vars (as appropriate) team + site (and owner if $ignoreOwner not false) + public function ownershipQueryVars( $ignoreOwner = false ) { + $queryVars = array(); - // =========== / OWNERSHIP HELPERS ============================================= - // =============================================================================== + // add site + // FOR V3.0 SITE + TEAM NOT YET USED, (BUT THIS'll WORK) + // $queryVars[] = zeroBSCRM_site(); + // add team + // FOR V3.0 SITE + TEAM NOT YET USED, (BUT THIS'll WORK) + // $queryVars[] = zeroBSCRM_team(); + // add owner + if ( ! $ignoreOwner ) { + $queryVars[] = zeroBSCRM_user(); + } - // =============================================================================== - // =========== ERROR HELPER FUNCS =============================================== - /* These are shared between DAL2 + DAL3, though are only included from v3.0 + */ + return $queryVars; + } + // this makes query str (as appropriate) team + site (and owner if $ignoreOwner not false) + // $table ONLY needed when is a LEFT JOIN or similar. + public function ownershipSQL( $ignoreOwner = false, $table = '' ) { + + // build + $q = ''; + $tableStr = ''; + if ( ! empty( $table ) ) { + $tableStr = $table . '.'; + } - // retrieve errors from dal error stack - public function getErrors($objTypeID=-1){ + // add site + // FOR V3.0 SITE + TEAM NOT YET USED, (BUT THIS'll WORK) + // $q = $this->spaceAnd($q).$tableStr.'zbs_site = %d'; - // all: - if ($objTypeID < 0) return $this->errorStack; + // add team + // FOR V3.0 SITE + TEAM NOT YET USED, (BUT THIS'll WORK) + // $q = $this->spaceAnd($q).$tableStr.'zbs_team = %d'; - // specific - if (is_array($this->errorStack) && isset($this->errorStack[$objTypeID])) return $this->errorStack[$objTypeID]; + // add owner + if ( ! $ignoreOwner ) { + $q = $this->spaceAnd( $q ) . $tableStr . 'zbs_owner = %d'; + } + return $q; + } - // ?? - return array(); - } + // =========== / OWNERSHIP HELPERS ============================================= + // =============================================================================== - // add error to dal error stack - public function addError($errorCode=-1,$objTypeID=-1,$errStr='',$extraParam=false){ + // =============================================================================== + // =========== ERROR HELPER FUNCS =============================================== + /* These are shared between DAL2 + DAL3, though are only included from v3.0 + */ - if ($objTypeID > 0 && !empty($errStr)){ + // retrieve errors from dal error stack + public function getErrors( $objTypeID = -1 ) { - // init - if (!isset($this->errorStack) || !is_array($this->errorStack)) $this->errorStack = array(); - if (!isset($this->errorStack[$objTypeID]) || !is_array($this->errorStack[$objTypeID])) $this->errorStack[$objTypeID] = array(); + // all: + if ( $objTypeID < 0 ) { + return $this->errorStack; + } - // if $errorCode, add to string - if ($errorCode > 0) $errStr .= ' ('.__('Error #','zero-bs-crm').$errorCode.')'; + // specific + if ( is_array( $this->errorStack ) && isset( $this->errorStack[ $objTypeID ] ) ) { + return $this->errorStack[ $objTypeID ]; + } - // add - $this->errorStack[$objTypeID][] = array('code'=>$errorCode,'str'=>$errStr,'param'=>$extraParam); - } - } + // ?? + return array(); + } - // =========== / ERROR HELPER FUNCS ============================================== - // =============================================================================== + // add error to dal error stack + public function addError( $errorCode = -1, $objTypeID = -1, $errStr = '', $extraParam = false ) { + if ( $objTypeID > 0 && ! empty( $errStr ) ) { + // init + if ( ! isset( $this->errorStack ) || ! is_array( $this->errorStack ) ) { + $this->errorStack = array(); + } + if ( ! isset( $this->errorStack[ $objTypeID ] ) || ! is_array( $this->errorStack[ $objTypeID ] ) ) { + $this->errorStack[ $objTypeID ] = array(); + } + // if $errorCode, add to string + if ( $errorCode > 0 ) { + $errStr .= ' (' . __( 'Error #', 'zero-bs-crm' ) . $errorCode . ')'; + } + // add + $this->errorStack[ $objTypeID ][] = array( + 'code' => $errorCode, + 'str' => $errStr, + 'param' => $extraParam, + ); + } + } -/* ====================================================== - DAL CRUD - ====================================================== */ + // =========== / ERROR HELPER FUNCS ============================================== + // =============================================================================== + /* + ====================================================== + DAL CRUD + ====================================================== */ - // =============================================================================== - // =========== OBJ LINKS ======================================================= + // =============================================================================== + // =========== OBJ LINKS ======================================================= - /** - * returns objects against an obj (e.g. company's against contact id 101) - * This is like getObjsLinksLinkedToObj, only it returns actual objs :) - * - * @param array $args Associative array of arguments - * obj array - * - * @return array result - */ - public function getObjsLinkedToObj($args=array()){ + /** + * returns objects against an obj (e.g. company's against contact id 101) + * This is like getObjsLinksLinkedToObj, only it returns actual objs :) + * + * @param array $args Associative array of arguments + * obj array + * + * @return array result + */ + public function getObjsLinkedToObj( $args = array() ) { - #} =========== LOAD ARGS ============== - $defaultArgs = array( + #} =========== LOAD ARGS ============== + $defaultArgs = array( - 'objtypefrom' => -1, - 'objtypeto' => -1, + 'objtypefrom' => -1, + 'objtypeto' => -1, - // either or here, to specify direction of relationship - 'objfromid' => -1, - 'objtoid' => -1, + // either or here, to specify direction of relationship + 'objfromid' => -1, + 'objtoid' => -1, - // this will be passed to the getCompanies(array()) func, if given - 'objRetrievePassthrough' => array(), + // this will be passed to the getCompanies(array()) func, if given + 'objRetrievePassthrough' => array(), - 'count' => false, // only return count + 'count' => false, // only return count - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // settings don't need owners yet :) + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // settings don't need owners yet :) - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // hard ignored for now :) - $ignoreowner = true; + // hard ignored for now :) + $ignoreowner = true; if ( empty( $objtypefrom ) ) { return false; } - if ($this->objTypeKey($objtypefrom) === -1) return false; + if ( $this->objTypeKey( $objtypefrom ) === -1 ) { + return false; + } if ( empty( $objtypeto ) ) { return false; } - if ($this->objTypeKey($objtypeto) === -1) return false; - - #} Check ID - $direction = 'from'; - $objfromid = (int)$objfromid; - $objtoid = (int)$objtoid; if ($objtoid > 0) $direction = 'to'; - - if ( - (!empty($objfromid) && $objfromid > 0) - || - (!empty($objtoid) && $objtoid > 0) - - ){ + if ( $this->objTypeKey( $objtypeto ) === -1 ) { + return false; + } - $res = array(); + #} Check ID + $direction = 'from'; + $objfromid = (int) $objfromid; + $objtoid = (int) $objtoid; + if ( $objtoid > 0 ) { + $direction = 'to'; + } - // get links - this could all be one query... optimise once other db objects moved over - $objLinks = $this->getObjsLinksLinkedToObj(array( - 'objtypefrom' => $objtypefrom, // contact - 'objtypeto' => $objtypeto, // company - 'objfromid' => $objfromid, //-1 or id - 'objtoid' => $objtoid)); + if ( + ( ! empty( $objfromid ) && $objfromid > 0 ) + || + ( ! empty( $objtoid ) && $objtoid > 0 ) - if ($count) { - if (is_array($objLinks)) - return count($objLinks); - else - return 0; - } + ) { - if (is_array($objLinks) && count($objLinks) > 0){ + $res = array(); - // make an id array (useful) - $idArray = array(); foreach ($objLinks as $l) { - - // switched direction - $xid = $l['objidto']; if ($direction == 'to') $xid = $l['objidfrom']; + // get links - this could all be one query... optimise once other db objects moved over + $objLinks = $this->getObjsLinksLinkedToObj( + array( + 'objtypefrom' => $objtypefrom, // contact + 'objtypeto' => $objtypeto, // company + 'objfromid' => $objfromid, // -1 or id + 'objtoid' => $objtoid, + ) + ); - if (!in_array($xid, $idArray)) $idArray[] = $xid; - } + if ( $count ) { + if ( is_array( $objLinks ) ) { + return count( $objLinks ); + } else { + return 0; + } + } - // load them all (type dependent) - switch ($objtypeto){ + if ( is_array( $objLinks ) && count( $objLinks ) > 0 ) { + // make an id array (useful) + $idArray = array(); foreach ( $objLinks as $l ) { - // not yet used, but will work :) - case ZBS_TYPE_CONTACT: - return $this->contacts->getContacts(array('inArr'=>$idArray)); - break; + // switched direction + $xid = $l['objidto']; + if ( $direction == 'to' ) { + $xid = $l['objidfrom']; + } - case ZBS_TYPE_COMPANY: - return $this->companies->getCompanies(array('inArr'=>$idArray)); - break; + if ( ! in_array( $xid, $idArray ) ) { + $idArray[] = $xid; + } + } - case ZBS_TYPE_QUOTE: - return $this->quotes->getQuotes(array('inArr'=>$idArray)); - break; + // load them all (type dependent) + switch ( $objtypeto ) { - case ZBS_TYPE_INVOICE: - return $this->invoices->getInvoices(array('inArr'=>$idArray)); - break; + // not yet used, but will work :) + case ZBS_TYPE_CONTACT: + return $this->contacts->getContacts( array( 'inArr' => $idArray ) ); + break; - case ZBS_TYPE_TRANSACTION: - return $this->transactions->getTransactions(array('inArr'=>$idArray)); - break; + case ZBS_TYPE_COMPANY: + return $this->companies->getCompanies( array( 'inArr' => $idArray ) ); + break; - case ZBS_TYPE_TASK: - return $this->events->getEvents(array('inArr'=>$idArray)); - break; + case ZBS_TYPE_QUOTE: + return $this->quotes->getQuotes( array( 'inArr' => $idArray ) ); + break; - case ZBS_TYPE_QUOTETEMPLATE: - return $this->quotetemplates->getQuotetemplate(array('inArr'=>$idArray)); - break; + case ZBS_TYPE_INVOICE: + return $this->invoices->getInvoices( array( 'inArr' => $idArray ) ); + break; - /* not used - case ZBS_TYPE_LOG: - return $this->logs->getLogs(array('inArr'=>$idArray)); - break; + case ZBS_TYPE_TRANSACTION: + return $this->transactions->getTransactions( array( 'inArr' => $idArray ) ); + break; - case ZBS_TYPE_LINEITEM: - return $this->events->getEvents(array('inArr'=>$idArray)); - break; + case ZBS_TYPE_TASK: + return $this->events->getEvents( array( 'inArr' => $idArray ) ); + break; - case ZBS_TYPE_TASK_REMINDER: - return $this->events->getEvents(array('inArr'=>$idArray)); - break; - */ - - } + case ZBS_TYPE_QUOTETEMPLATE: + return $this->quotetemplates->getQuotetemplate( array( 'inArr' => $idArray ) ); + break; + /* + not used + case ZBS_TYPE_LOG: + return $this->logs->getLogs(array('inArr'=>$idArray)); + break; - } + case ZBS_TYPE_LINEITEM: + return $this->events->getEvents(array('inArr'=>$idArray)); + break; + case ZBS_TYPE_TASK_REMINDER: + return $this->events->getEvents(array('inArr'=>$idArray)); + break; + */ + } + } - return $res; + return $res; - } // / if ID + } // / if ID - return false; + return false; + } - } + /** + * returns object link lines against an obj (e.g. link id, company id's against contact id 101) + * + * @param array $args Associative array of arguments + * objtypeid, objid + * + * @return array result + */ + public function getObjsLinksLinkedToObj( $args = array() ) { - /** - * returns object link lines against an obj (e.g. link id, company id's against contact id 101) - * - * @param array $args Associative array of arguments - * objtypeid, objid - * - * @return array result - */ - public function getObjsLinksLinkedToObj($args=array()){ + #} =========== LOAD ARGS ============== + $defaultArgs = array( - #} =========== LOAD ARGS ============== - $defaultArgs = array( + 'objtypefrom' => -1, + 'objtypeto' => -1, - 'objtypefrom' => -1, - 'objtypeto' => -1, + // either or here, to specify direction of relationship + // if 'direction' = 'both', it'll check both + 'objfromid' => -1, + 'objtoid' => -1, - // either or here, to specify direction of relationship - // if 'direction' = 'both', it'll check both - 'objfromid' => -1, - 'objtoid' => -1, + 'direction' => 'from', // from, to, both (both checks for both id's and is used to validate if links exist) - 'direction' => 'from', // from, to, both (both checks for both id's and is used to validate if links exist) + 'count' => false, // only return count - 'count' => false, // only return count + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // settings don't need owners yet :) - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // settings don't need owners yet :) + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + // hard ignored for now + $ignoreowner = true; - // hard ignored for now - $ignoreowner = true; - if ( empty( $objtypefrom ) ) { return false; } - if ($this->objTypeKey($objtypefrom) === -1) return false; + if ( $this->objTypeKey( $objtypefrom ) === -1 ) { + return false; + } if ( empty( $objtypeto ) ) { return false; } - if ($this->objTypeKey($objtypeto) === -1) return false; + if ( $this->objTypeKey( $objtypeto ) === -1 ) { + return false; + } - #} Check ID - $objfromid = (int)$objfromid; - $objtoid = (int)$objtoid; if ($objtoid > 0 && $direction != "both") $direction = 'to'; + #} Check ID + $objfromid = (int) $objfromid; + $objtoid = (int) $objtoid; + if ( $objtoid > 0 && $direction != 'both' ) { + $direction = 'to'; + } - if ( - (!empty($objfromid) && $objfromid > 0) - || - (!empty($objtoid) && $objtoid > 0) + if ( + ( ! empty( $objfromid ) && $objfromid > 0 ) + || + ( ! empty( $objtoid ) && $objtoid > 0 ) - ){ + ) { - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['objlinks']; + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['objlinks']; - #} ============= WHERE ================ + #} ============= WHERE ================ - #} Add - $wheres['zbsol_objtype_from'] = array('zbsol_objtype_from','=','%s',$objtypefrom); - $wheres['zbsol_objtype_to'] = array('zbsol_objtype_to','=','%s',$objtypeto); + #} Add + $wheres['zbsol_objtype_from'] = array( 'zbsol_objtype_from', '=', '%s', $objtypefrom ); + $wheres['zbsol_objtype_to'] = array( 'zbsol_objtype_to', '=', '%s', $objtypeto ); - // which direction? - if ($direction == 'from' || $direction == 'both') $wheres['zbsol_objid_from'] = array('zbsol_objid_from','=','%s',$objfromid); - if ($direction == 'to' || $direction == 'both') $wheres['zbsol_objid_to'] = array('zbsol_objid_to','=','%s',$objtoid); + // which direction? + if ( $direction == 'from' || $direction == 'both' ) { + $wheres['zbsol_objid_from'] = array( 'zbsol_objid_from', '=', '%s', $objfromid ); + } + if ( $direction == 'to' || $direction == 'both' ) { + $wheres['zbsol_objid_to'] = array( 'zbsol_objid_to', '=', '%s', $objtoid ); + } - #} ============ / WHERE ============== + #} ============ / WHERE ============== - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,10000); + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 10000 ); - try { + try { - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - } catch (Exception $e){ + } catch ( Exception $e ) { - #} General SQL Err - $this->catchSQLError($e); + #} General SQL Err + $this->catchSQLError( $e ); - } + } - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - // if count? - if ($count) return count($potentialRes); + // if count? + if ( $count ) { + return count( $potentialRes ); + } - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $resArr = $this->tidy_objlink($resDataLine); + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - $res[] = $resArr; + // tidy + $resArr = $this->tidy_objlink( $resDataLine ); - } - } + $res[] = $resArr; - // if count? - if ($count) return 0; + } + } - return $res; + // if count? + if ( $count ) { + return 0; + } - } // / if ID + return $res; - return false; + } // / if ID - } + return false; + } - /** - * returns ID of first obj of link type (to obj) - * e.g. ID first invoice linked to transaction ID (X) - * (useful where transactions:invoices are only ever linked 1:1) - * - * @param array $args Associative array of arguments - * objtypeid, objid - * - * @return array result - */ - public function getFirstIDLinkedToObj($args=array()){ + /** + * returns ID of first obj of link type (to obj) + * e.g. ID first invoice linked to transaction ID (X) + * (useful where transactions:invoices are only ever linked 1:1) + * + * @param array $args Associative array of arguments + * objtypeid, objid + * + * @return array result + */ + public function getFirstIDLinkedToObj( $args = array() ) { - #} =========== LOAD ARGS ============== - $defaultArgs = array( + #} =========== LOAD ARGS ============== + $defaultArgs = array( - 'objtypefrom' => -1, - 'objtypeto' => -1, - 'objfromid' => -1, + 'objtypefrom' => -1, + 'objtypeto' => -1, + 'objfromid' => -1, - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // settings don't need owners yet :) + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // settings don't need owners yet :) - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // hard ignored for now - $ignoreowner = true; + // hard ignored for now + $ignoreowner = true; if ( empty( $objtypefrom ) ) { return false; } - if ($this->objTypeKey($objtypefrom) === -1) return false; + if ( $this->objTypeKey( $objtypefrom ) === -1 ) { + return false; + } if ( empty( $objtypeto ) ) { return false; } - if ($this->objTypeKey($objtypeto) === -1) return false; - - #} Check ID - $objfromid = (int)$objfromid; + if ( $this->objTypeKey( $objtypeto ) === -1 ) { + return false; + } - if (!empty($objfromid) && $objfromid > 0){ + #} Check ID + $objfromid = (int) $objfromid; - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + if ( ! empty( $objfromid ) && $objfromid > 0 ) { - #} Build query - $query = "SELECT zbsol_objid_to FROM ".$ZBSCRM_t['objlinks']; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} ============= WHERE ================ + #} Build query + $query = 'SELECT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks']; - #} Add - $wheres['zbsol_objtype_from'] = array('zbsol_objtype_from','=','%s',$objtypefrom); - $wheres['zbsol_objtype_to'] = array('zbsol_objtype_to','=','%s',$objtypeto); - $wheres['zbsol_objid_from'] = array('zbsol_objid_from','=','%s',$objfromid); - + #} ============= WHERE ================ - #} ============ / WHERE ============== + #} Add + $wheres['zbsol_objtype_from'] = array( 'zbsol_objtype_from', '=', '%s', $objtypefrom ); + $wheres['zbsol_objtype_to'] = array( 'zbsol_objtype_to', '=', '%s', $objtypeto ); + $wheres['zbsol_objid_from'] = array( 'zbsol_objid_from', '=', '%s', $objfromid ); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} ============ / WHERE ============== - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - try { + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_var($queryObj); - if ($potentialRes > -1) return (int)$potentialRes; + try { - } catch (Exception $e){ + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_var( $queryObj ); + if ( $potentialRes > -1 ) { + return (int) $potentialRes; + } + } catch ( Exception $e ) { - #} General SQL Err - $this->catchSQLError($e); + #} General SQL Err + $this->catchSQLError( $e ); - } + } + } // / if ID - } // / if ID + return false; + } - return false; - - } - - - - - - /** - * adds or updates a link object - * E.G. Contact -> Company - * this says "match obj X with obj Y" (effectively 'tagging' it) - * Using this generic format, but as of v2.5+ there's only contact->company links in here - * - * @param array $args Associative array of arguments - * id (if update - probably never used here), data(objtype,objid,tagid) - * - * @return int line ID - */ - public function addUpdateObjLink($args=array()){ + /** + * adds or updates a link object + * E.G. Contact -> Company + * this says "match obj X with obj Y" (effectively 'tagging' it) + * Using this generic format, but as of v2.5+ there's only contact->company links in here + * + * @param array $args Associative array of arguments + * id (if update - probably never used here), data(objtype,objid,tagid) + * + * @return int line ID + */ + public function addUpdateObjLink( $args = array() ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'id' => -1, + 'id' => -1, - // OWNERS will all be set to -1 for objlinks for now :) - //'owner' => -1 + // OWNERS will all be set to -1 for objlinks for now :) + // 'owner' => -1 - // fields (directly) - 'data' => array( + // fields (directly) + 'data' => array( - 'objtypefrom' => -1, - 'objtypeto' => -1, - 'objfromid' => -1, - 'objtoid' => -1 + 'objtypefrom' => -1, + 'objtypeto' => -1, + 'objfromid' => -1, + 'objtoid' => -1, - ) + ), - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ // check obtype is completed + legit if ( empty( $data['objtypefrom'] ) ) { return false; } - if ($this->objTypeKey($data['objtypefrom']) === -1) return false; + if ( $this->objTypeKey( $data['objtypefrom'] ) === -1 ) { + return false; + } if ( empty( $data['objtypeto'] ) ) { return false; } - if ($this->objTypeKey($data['objtypeto']) === -1) return false; - - // if owner = -1, add current - // for now, all -1 - not needed yet (makes tags dupe e.g.) if (!isset($owner) || $owner === -1) $owner = zeroBSCRM_user(); - $owner = -1; - - #} check obj ids - if (empty($data['objfromid']) || $data['objfromid'] < 1 || empty($data['objtoid']) || $data['objtoid'] < 1) return false; - - #} ========= / CHECK FIELDS =========== - - #} Check if ID present - $id = (int)$id; - if (!empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['objlinks'], - array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $owner, - - // fields - 'zbsol_objtype_from' => $data['objtypefrom'], - 'zbsol_objtype_to' => $data['objtypeto'], - 'zbsol_objid_from' => $data['objfromid'], - 'zbsol_objid_to' => $data['objtoid'] - ), - array( // where - 'ID' => $id - ), - array( // field data types - '%d', - '%d', - '%d', - '%d', - '%d' - ), - array( // where data types - '%d' - )) !== false){ - - // Successfully updated - Return id - return $id; + if ( $this->objTypeKey( $data['objtypeto'] ) === -1 ) { + return false; + } - } else { + // if owner = -1, add current + // for now, all -1 - not needed yet (makes tags dupe e.g.) if (!isset($owner) || $owner === -1) $owner = zeroBSCRM_user(); + $owner = -1; - // FAILED update - return false; + #} check obj ids + if ( empty( $data['objfromid'] ) || $data['objfromid'] < 1 || empty( $data['objtoid'] ) || $data['objtoid'] < 1 ) { + return false; + } - } + #} ========= / CHECK FIELDS =========== - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['objlinks'], - array( + #} Check if ID present + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - // ownership - 'zbs_site' => zeroBSCRM_site(), - 'zbs_team' => zeroBSCRM_team(), - 'zbs_owner' => $owner, + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - // fields - 'zbsol_objtype_from' => $data['objtypefrom'], - 'zbsol_objtype_to' => $data['objtypeto'], - 'zbsol_objid_from' => $data['objfromid'], - 'zbsol_objid_to' => $data['objtoid'] - ), - array( // field data types - '%d', // site - '%d', // team - '%d', // owner + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['objlinks'], + array( - '%d', - '%d', - '%d', - '%d' - ) ) > 0){ + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $owner, + + // fields + 'zbsol_objtype_from' => $data['objtypefrom'], + 'zbsol_objtype_to' => $data['objtypeto'], + 'zbsol_objid_from' => $data['objfromid'], + 'zbsol_objid_to' => $data['objtoid'], + ), + array( // where + 'ID' => $id, + ), + array( // field data types + '%d', + '%d', + '%d', + '%d', + '%d', + ), + array( // where data types + '%d', + ) + ) !== false ) { - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - return $newID; + // Successfully updated - Return id + return $id; - } else { + } else { - #} Failed to Insert - return false; + // FAILED update + return false; - } + } + } else { - } + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['objlinks'], + array( - return false; - - } - - /** - * adds or updates object - object link against an obj - * this says "match company X,Y,Z with contact Y" - * - * @param array $args Associative array of arguments - * objtype,objid,tags (array of tagids) - * - * @return array $tags - */ - public function addUpdateObjLinks($args=array()){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'owner' => -1, - - 'objtypefrom' => -1, - 'objtypeto' => -1, - 'objfromid' => -1, - 'objtoids' => -1, // array of ID's - - 'mode' => 'replace' // replace|append|remove - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + // ownership + 'zbs_site' => zeroBSCRM_site(), + 'zbs_team' => zeroBSCRM_team(), + 'zbs_owner' => $owner, + + // fields + 'zbsol_objtype_from' => $data['objtypefrom'], + 'zbsol_objtype_to' => $data['objtypeto'], + 'zbsol_objid_from' => $data['objfromid'], + 'zbsol_objid_to' => $data['objtoid'], + ), + array( // field data types + '%d', // site + '%d', // team + '%d', // owner + + '%d', + '%d', + '%d', + '%d', + ) + ) > 0 ) { + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + return $newID; - #} ========== CHECK FIELDS ============ + } else { - // check obtype is completed + legit - if ( empty( $objtypefrom ) ) { - return false; - } - if ($this->objTypeKey($objtypefrom) === -1) return false; - if ( empty( $objtypeto ) ) { - return false; - } - if ($this->objTypeKey($objtypeto) === -1) return false; + #} Failed to Insert + return false; - // if owner = -1, add current - if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $owner = zeroBSCRM_user(); + } } - // tagging id - $objfromid = (int)$objfromid; if (empty($objfromid) || $objfromid < 1) return false; - - // to obj list - if (!is_array($objtoids)) return false; - - // mode - if (gettype($mode) != 'string' || !in_array($mode, array('replace','append','remove'))) return false; + return false; + } - #} ========= / CHECK FIELDS =========== + /** + * adds or updates object - object link against an obj + * this says "match company X,Y,Z with contact Y" + * + * @param array $args Associative array of arguments + * objtype,objid,tags (array of tagids) + * + * @return array $tags + */ + public function addUpdateObjLinks( $args = array() ) { - switch ($mode){ + global $ZBSCRM_t, $wpdb; - case 'replace': - - // cull all previous - $deleted = $this->deleteObjLinks(array( - 'objtypefrom' => $objtypefrom, // contact - 'objtypeto' => $objtypeto, // company - 'objfromid' => $objfromid)); // where contact id = + #} ============ LOAD ARGS ============= + $defaultArgs = array( - // cycle through & add - foreach ($objtoids as $objtoid){ + 'owner' => -1, - $added = $this->addUpdateObjLink(array( - 'data'=>array( - 'objtypefrom' => $objtypefrom, - 'objtypeto' => $objtypeto, - 'objfromid' => $objfromid, - 'objtoid' => $objtoid, - 'owner' => $owner - ))); + 'objtypefrom' => -1, + 'objtypeto' => -1, + 'objfromid' => -1, + 'objtoids' => -1, // array of ID's + 'mode' => 'replace', // replace|append|remove - } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - break; + #} ========== CHECK FIELDS ============ - case 'append': + // check obtype is completed + legit + if ( empty( $objtypefrom ) ) { + return false; + } + if ( $this->objTypeKey( $objtypefrom ) === -1 ) { + return false; + } + if ( empty( $objtypeto ) ) { + return false; + } + if ( $this->objTypeKey( $objtypeto ) === -1 ) { + return false; + } - // get existing - $objLinks = $this->getObjsLinksLinkedToObj(array( - 'objtypefrom' => $objtypefrom, // contact - 'objtypeto' => $objtypeto, // company - 'objfromid' => $objfromid)); + // if owner = -1, add current + if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $owner = zeroBSCRM_user(); + } - // make just ids - $existingLinkIDs = array(); foreach ($objLinks as $l) $existingLinkIDs[] = $l['id']; + // tagging id + $objfromid = (int) $objfromid; + if ( empty( $objfromid ) || $objfromid < 1 ) { + return false; + } - // cycle through& add - foreach ($objtoids as $objtoid){ + // to obj list + if ( ! is_array( $objtoids ) ) { + return false; + } - if (!in_array($objtoid,$existingLinkIDs)){ + // mode + if ( gettype( $mode ) != 'string' || ! in_array( $mode, array( 'replace', 'append', 'remove' ) ) ) { + return false; + } - // add a link - $this->addUpdateObjLink(array( - 'data'=>array( - 'objtypefrom' => $objtypefrom, - 'objtypeto' => $objtypeto, - 'objfromid' => $objfromid, - 'objtoid' => $objtoid, - 'owner' => $owner - ))); + #} ========= / CHECK FIELDS =========== + + switch ( $mode ) { + + case 'replace': + // cull all previous + $deleted = $this->deleteObjLinks( + array( + 'objtypefrom' => $objtypefrom, // contact + 'objtypeto' => $objtypeto, // company + 'objfromid' => $objfromid, + ) + ); // where contact id = + + // cycle through & add + foreach ( $objtoids as $objtoid ) { + + $added = $this->addUpdateObjLink( + array( + 'data' => array( + 'objtypefrom' => $objtypefrom, + 'objtypeto' => $objtypeto, + 'objfromid' => $objfromid, + 'objtoid' => $objtoid, + 'owner' => $owner, + ), + ) + ); - } + } - } + break; - break; + case 'append': + // get existing + $objLinks = $this->getObjsLinksLinkedToObj( + array( + 'objtypefrom' => $objtypefrom, // contact + 'objtypeto' => $objtypeto, // company + 'objfromid' => $objfromid, + ) + ); + + // make just ids + $existingLinkIDs = array(); + foreach ( $objLinks as $l ) { + $existingLinkIDs[] = $l['id']; + } - case 'remove': + // cycle through& add + foreach ( $objtoids as $objtoid ) { - // cycle through & remove links - foreach ($objtoids as $objtoid){ + if ( ! in_array( $objtoid, $existingLinkIDs ) ) { - // add a link - $this->deleteObjLinks(array( - 'objtypefrom' => $objtypefrom, // contact - 'objtypeto' => $objtypeto, // company - 'objfromid' => $objfromid, - 'objtoid' => $objtoid)); // where contact id = + // add a link + $this->addUpdateObjLink( + array( + 'data' => array( + 'objtypefrom' => $objtypefrom, + 'objtypeto' => $objtypeto, + 'objfromid' => $objfromid, + 'objtoid' => $objtoid, + 'owner' => $owner, + ), + ) + ); + } + } - } + break; - break; + case 'remove': + // cycle through & remove links + foreach ( $objtoids as $objtoid ) { + // add a link + $this->deleteObjLinks( + array( + 'objtypefrom' => $objtypefrom, // contact + 'objtypeto' => $objtypeto, // company + 'objfromid' => $objfromid, + 'objtoid' => $objtoid, + ) + ); // where contact id = - } + } + break; - return false; + } - } + return false; + } - /** - * deletes all object links for a specific obj - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteObjLinks($args=array()){ + /** + * deletes all object links for a specific obj + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteObjLinks( $args = array() ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'objtypefrom' => -1, - 'objtypeto' => -1, - 'objfromid' => -1, - 'objtoid' => -1 // only toid/fromid to be set if want to delete all contact->company links + 'objtypefrom' => -1, + 'objtypeto' => -1, + 'objfromid' => -1, + 'objtoid' => -1, // only toid/fromid to be set if want to delete all contact->company links - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ // check obtype is completed + legit if ( empty( $objtypefrom ) ) { return false; } - if ($this->objTypeKey($objtypefrom) === -1) return false; + if ( $this->objTypeKey( $objtypefrom ) === -1 ) { + return false; + } if ( empty( $objtypeto ) ) { return false; } - if ($this->objTypeKey($objtypeto) === -1) return false; - - // obj id - $objfromid = (int)$objfromid; $objtoid = (int)$objtoid; - if ( - (empty($objfromid) || $objfromid < 1) - && - (empty($objtoid) || $objtoid < 1) - ) return false; - - // CHECK PERMISSIONS? - - #} ========= / CHECK FIELDS =========== - - // basics - $where = array( // where - 'zbsol_objtype_from' => $objtypefrom, - 'zbsol_objtype_to' => $objtypeto - ); - - $whereFormat = array( // where - '%d', - '%d' - ); - - // any to add? - if (!empty($objfromid) && $objfromid > 0){ - $where['zbsol_objid_from'] = $objfromid; - $whereFormat[] = '%d'; - } - if (!empty($objtoid) && $objtoid > 0){ - $where['zbsol_objid_to'] = $objtoid; - $whereFormat[] = '%d'; - } - - // brutal - return $wpdb->delete( - $ZBSCRM_t['objlinks'], - $where, - $whereFormat); + if ( $this->objTypeKey( $objtypeto ) === -1 ) { + return false; + } - } + // obj id + $objfromid = (int) $objfromid; + $objtoid = (int) $objtoid; + if ( + ( empty( $objfromid ) || $objfromid < 1 ) + && + ( empty( $objtoid ) || $objtoid < 1 ) + ) { + return false; + } + // CHECK PERMISSIONS? - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_objlink($obj=false){ + #} ========= / CHECK FIELDS =========== - $res = false; + // basics + $where = array( // where + 'zbsol_objtype_from' => $objtypefrom, + 'zbsol_objtype_to' => $objtypeto, + ); - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ + $whereFormat = array( // where + '%d', + '%d', + ); - $res['objtypefrom'] = $obj->zbsol_objtype_from; - $res['objtypeto'] = $obj->zbsol_objtype_to; - $res['objidfrom'] = $obj->zbsol_objid_from; - $res['objidto'] = $obj->zbsol_objid_to; + // any to add? + if ( ! empty( $objfromid ) && $objfromid > 0 ) { + $where['zbsol_objid_from'] = $objfromid; + $whereFormat[] = '%d'; + } + if ( ! empty( $objtoid ) && $objtoid > 0 ) { + $where['zbsol_objid_to'] = $objtoid; + $whereFormat[] = '%d'; + } - } + // brutal + return $wpdb->delete( + $ZBSCRM_t['objlinks'], + $where, + $whereFormat + ); + } - return $res; + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_objlink( $obj = false ) { + $res = false; - } + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ - // =========== OBJ LINKS ===================================================== - // =============================================================================== + $res['objtypefrom'] = $obj->zbsol_objtype_from; + $res['objtypeto'] = $obj->zbsol_objtype_to; + $res['objidfrom'] = $obj->zbsol_objid_from; + $res['objidto'] = $obj->zbsol_objid_to; + } + return $res; + } + // =========== OBJ LINKS ===================================================== + // =============================================================================== - // =============================================================================== - // =========== SETTINGS ====================================================== + // =============================================================================== + // =========== SETTINGS ====================================================== - /** - * Wrapper, use $this->setting($key) for easy retrieval of singular - * Simplifies $this->getSetting - * - * @param string key - * - * @return bool result - */ - public function setting( $key = '', $default = false, $accept_cached = false){ + /** + * Wrapper, use $this->setting($key) for easy retrieval of singular + * Simplifies $this->getSetting + * + * @param string key + * + * @return bool result + */ + public function setting( $key = '', $default = false, $accept_cached = false ) { if ( ! empty( $key ) ) { return $this->getSetting( array( @@ -1742,48 +1964,50 @@ public function setting( $key = '', $default = false, $accept_cached = false){ ); } - return $default; - } + return $default; + } - /** - * Wrapper, use $this->userSetting($key) for easy retrieval of singular setting FOR USER ID - * Simplifies $this->getSetting - * Specific for USER settings, this prefixes setting keys with usrset_ID_ - * - * @param string key - * - * @return bool result - */ - public function userSetting($userID=-1,$key='',$default=false){ + /** + * Wrapper, use $this->userSetting($key) for easy retrieval of singular setting FOR USER ID + * Simplifies $this->getSetting + * Specific for USER settings, this prefixes setting keys with usrset_ID_ + * + * @param string key + * + * @return bool result + */ + public function userSetting( $userID = -1, $key = '', $default = false ) { - if (!empty($key) && $userID > 0){ + if ( ! empty( $key ) && $userID > 0 ) { - return $this->getSetting(array( + return $this->getSetting( + array( - // old way of doing it'key' => $this->getUserSettingPrefix($userID).$key, - 'key' => $this->userSettingPrefix.$key, - 'fullDetails' => false, - 'default' => $default, + // old way of doing it'key' => $this->getUserSettingPrefix($userID).$key, + 'key' => $this->userSettingPrefix . $key, + 'fullDetails' => false, + 'default' => $default, - // this makes it 'per user' - 'ownedBy' => $userID + // this makes it 'per user' + 'ownedBy' => $userID, - )); + ) + ); - } + } - return $default; - } + return $default; + } - /** - * returns full setting line +- details - * - * @param array $args Associative array of arguments - * key, fullDetails, default - * - * @return array result - */ - public function getSetting($args=array()){ + /** + * returns full setting line +- details + * + * @param array $args Associative array of arguments + * key, fullDetails, default + * + * @return array result + */ + public function getSetting( $args = array() ) { $key = isset( $args['key'] ) ? $args['key'] : false; $fullDetails = isset( $args['fullDetails'] ) ? $args['fullDetails'] : false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -1792,145 +2016,163 @@ public function getSetting($args=array()){ return static::mitigation_cache_for_issue_3504_single_setting( $key ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable } - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - 'key' => false, - 'default' => false, - 'fullDetails' => false, // set this to 1 and get ID|key|val, rather than just the val - - // permissions - these are currently only used by screenoptions - 'ignoreowner' => true, // this'll let you not-check the owner of obj - 'ownedBy' => -1, + #} =========== LOAD ARGS ============== + $defaultArgs = array( - // returns scalar ID of line - 'onlyID' => false, + 'key' => false, + 'default' => false, + 'fullDetails' => false, // set this to 1 and get ID|key|val, rather than just the val - // whether or not to accept cached variant. - // Added in gh-2019, we often recall this function on one load, this allows us to accept a once-loaded version - 'accept_cached' => false, + // permissions - these are currently only used by screenoptions + 'ignoreowner' => true, // this'll let you not-check the owner of obj + 'ownedBy' => -1, - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + // returns scalar ID of line + 'onlyID' => false, - #} Check key - if (!empty($key)){ + // whether or not to accept cached variant. + // Added in gh-2019, we often recall this function on one load, this allows us to accept a once-loaded version + 'accept_cached' => false, - // if accepting a cached obj and is present, pass that to save the query - // (only do so on singular return step, not full details) - if ( !$fullDetails && $accept_cached ){ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - $cached = $this->get_cache_var( 'setting_' . $key ); + #} Check key + if ( ! empty( $key ) ) { - if ( $cached ){ + // if accepting a cached obj and is present, pass that to save the query + // (only do so on singular return step, not full details) + if ( ! $fullDetails && $accept_cached ) { - return $cached; + $cached = $this->get_cache_var( 'setting_' . $key ); - } + if ( $cached ) { - } + return $cached; - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + } + } - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['settings']; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} ============= WHERE ================ + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['settings']; - #} Add ID - $wheres['zbsset_key'] = array('zbsset_key','=','%s',$key); + #} ============= WHERE ================ - #} Owned by - if (!empty($ownedBy) && $ownedBy > 0){ - - // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) - // but this is only here until MIGRATED to db2 globally - //$wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); - // Use obj links now - $wheres['ownedBy'] = array('zbs_owner','=','%s',$ownedBy); + #} Add ID + $wheres['zbsset_key'] = array( 'zbsset_key', '=', '%s', $key ); - } + #} Owned by + if ( ! empty( $ownedBy ) && $ownedBy > 0 ) { + // would never hard-type this in (would make generic as in buildWPMetaQueryWhere) + // but this is only here until MIGRATED to db2 globally + // $wheres['incompany'] = array('ID','IN','(SELECT DISTINCT post_id FROM '.$wpdb->prefix."postmeta WHERE meta_key = 'zbs_company' AND meta_value = %d)",$inCompany); + // Use obj links now + $wheres['ownedBy'] = array( 'zbs_owner', '=', '%s', $ownedBy ); - #} ============ / WHERE ============== + } - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} ============ / WHERE ============== - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - try { + try { - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - } catch (Exception $e){ + } catch ( Exception $e ) { - #} General SQL Err - $this->catchSQLError($e); + #} General SQL Err + $this->catchSQLError( $e ); - } + } - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - // Has results, tidy + return - - // Only ID? return it directly - if ($onlyID === true) return $potentialRes->ID; + // Has results, tidy + return - // full line or scalar setting val - if ( $fullDetails ){ + // Only ID? return it directly + if ( $onlyID === true ) { + return $potentialRes->ID; + } - $setting = $this->tidy_setting($potentialRes); + // full line or scalar setting val + if ( $fullDetails ) { - } else { + $setting = $this->tidy_setting( $potentialRes ); - $setting = $this->tidy_settingSingular($potentialRes); + } else { - // We only update the mitigation cache when $fullDetails is false. - static::mitigation_cache_for_issue_3504_set_single_setting( $key, $setting ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $setting = $this->tidy_settingSingular( $potentialRes ); - // cache (commonly retrieved) - $this->update_cache_var( 'setting_' . $key, $setting ); + // We only update the mitigation cache when $fullDetails is false. + static::mitigation_cache_for_issue_3504_set_single_setting( $key, $setting ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } + // cache (commonly retrieved) + $this->update_cache_var( 'setting_' . $key, $setting ); - return $setting; + } - } + return $setting; - } // / if ID + } + } // / if ID if ( ! $fullDetails ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable // We only update the mitigation cache when $fullDetails is false. static::mitigation_cache_for_issue_3504_set_single_setting( $key, $default ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable } - return $default; - - } - + return $default; + } - /** - * returns all settings as settings arr (later add autoload) - * - * @param array $args Associative array of arguments - * - * @return array of settings lines - */ - public function getSettings($args=array()){ + /** + * returns all settings as settings arr (later add autoload) + * + * @param array $args Associative array of arguments + * + * @return array of settings lines + */ + public function getSettings( $args = array() ) { // If we have already loaded all settings in our cache, return them. // In this function we won't care if the values have changed or not because when they become invalid due to other functions, these functions should reset the cache. if ( static::mitigation_cache_for_issue_3504_contains_all_settings() ) { @@ -1939,76 +2181,100 @@ public function getSettings($args=array()){ // Reseting any single settings we may have already loaded. static::reset_mitigation_cache_for_issue_3504(); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'autoloadOnly' => true, + 'fullDetails' => false, // if true returns inc id etc. - 'autoloadOnly' => true, - 'fullDetails' => false, // if true returns inc id etc. + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // settings don't need owners yet :) - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // settings don't need owners yet :) + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} ========== CHECK FIELDS ============ - #} ========== CHECK FIELDS ============ + // check obtype is legit + // autoload? - // check obtype is legit - // autoload? + $fields = 'ID,zbsset_key,zbsset_val'; + if ( $fullDetails ) { + $fields = '*'; + } - $fields = 'ID,zbsset_key,zbsset_val'; - if ($fullDetails) $fields = '*'; + // always ignore owner for now (settings global) + $ignoreowner = true; - // always ignore owner for now (settings global) - $ignoreowner = true; - - #} ========= / CHECK FIELDS =========== + #} ========= / CHECK FIELDS =========== - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} Build query - $query = "SELECT $fields FROM ".$ZBSCRM_t['settings']; + #} Build query + $query = "SELECT $fields FROM " . $ZBSCRM_t['settings']; - #} ============= WHERE ================ + #} ============= WHERE ================ - #} autoload? + #} autoload? - #} ============ / WHERE =============== + #} ============ / WHERE =============== - #} Build out any WHERE clauses - $wheresArr= $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','ASC') . $this->buildPaging(0,10000); + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'ASC' ) . $this->buildPaging( 0, 10000 ); - try { + try { - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - } catch (Exception $e){ + } catch ( Exception $e ) { - #} General SQL Err - $this->catchSQLError($e); + #} General SQL Err + $this->catchSQLError( $e ); - } + } - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { // We are only caching the singular setting (i.e. the value), because it is good enough. static::mitigation_cache_for_issue_3504_set_single_setting( $resDataLine->zbsset_key, $this->tidy_settingSingular( $resDataLine ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -2018,120 +2284,138 @@ public function getSettings($args=array()){ } else { $res[ $resDataLine->zbsset_key ] = $this->tidy_settingSingular( $resDataLine ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - } - } + } + } static::mitigation_cache_for_issue_3504_set_contains_all( true ); return $res; - } + } + + /** + * Wrapper, use $this->updateSetting($key,$val) for easy update of setting + * Uses $this->addUpdateSetting + * + * @param string key + * @param string value + * + * @return bool result + */ + public function updateSetting( $key = '', $val = '' ) { - /** - * Wrapper, use $this->updateSetting($key,$val) for easy update of setting - * Uses $this->addUpdateSetting - * - * @param string key - * @param string value - * - * @return bool result - */ - public function updateSetting($key='',$val=''){ + if ( ! empty( $key ) ) { - if (!empty($key)){ + return $this->addUpdateSetting( + array( - return $this->addUpdateSetting(array( + 'data' => array( - 'data' => array( + 'key' => $key, + 'val' => $val, + ), - 'key' => $key, - 'val' => $val - ) + ) + ); - )); + } - } + return false; + } - return false; - } + /** + * Wrapper, use $this->updateSetting($key,$val) for easy update of setting + * Uses $this->addUpdateSetting + * + * @param string key + * @param string value + * + * @return bool result + */ + public function updateUserSetting( $userID = -1, $key = '', $val = '' ) { - /** - * Wrapper, use $this->updateSetting($key,$val) for easy update of setting - * Uses $this->addUpdateSetting - * - * @param string key - * @param string value - * - * @return bool result - */ - public function updateUserSetting($userID=-1,$key='',$val=''){ + // if -1 passed use current user? - // if -1 passed use current user? + if ( ! empty( $key ) && $userID > 0 ) { - if (!empty($key) && $userID > 0){ + // because the following addUpdateSetting is dumb to owners (e.g. can't update 'per owner') + // we must set perOwnerSetting to force 1 setting per key per user (owner) - // because the following addUpdateSetting is dumb to owners (e.g. can't update 'per owner') - // we must set perOwnerSetting to force 1 setting per key per user (owner) + return $this->addUpdateSetting( + array( - return $this->addUpdateSetting(array( + 'owner' => $userID, + 'data' => array( - 'owner' => $userID, - 'data' => array( + // old way of doing it'key' => $this->getUserSettingPrefix($userID).$key, + 'key' => $this->userSettingPrefix . $key, + 'val' => $val, + ), - // old way of doing it'key' => $this->getUserSettingPrefix($userID).$key, - 'key' => $this->userSettingPrefix.$key, - 'val' => $val, - ), + 'perOwnerSetting' => true, - 'perOwnerSetting' => true + ) + ); - )); + } - } + return false; + } - return false; - } + /** + * adds or updates a setting object + * ... for a quicker wrapper, use $this->updateSetting($key,$val) + * + * @param array $args Associative array of arguments + * id (not req.), owner (not req.) data -> key/val + * + * @return int line ID + */ + public function addUpdateSetting( $args = array() ) { - /** - * adds or updates a setting object - * ... for a quicker wrapper, use $this->updateSetting($key,$val) - * - * @param array $args Associative array of arguments - * id (not req.), owner (not req.) data -> key/val - * - * @return int line ID - */ - public function addUpdateSetting($args=array()){ + global $ZBSCRM_t, $wpdb; - global $ZBSCRM_t,$wpdb; + #} ============ LOAD ARGS ============= + $defaultArgs = array( - #} ============ LOAD ARGS ============= - $defaultArgs = array( + 'id' => -1, + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // meta don't need owners yet :) + // not anymore! use this for screenoptions, will be ignored unless specifically set + 'owner' => -1, - 'id' => -1, - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // meta don't need owners yet :) - // not anymore! use this for screenoptions, will be ignored unless specifically set - 'owner' => -1, + // fields (directly) + 'data' => array( - // fields (directly) - 'data' => array( + 'key' => '', + 'val' => '', - 'key' => '', - 'val' => '', - - ), + ), - 'perOwnerSetting' => false // if set to true this'll make sure only 1 key per 'owner' (potentially multi-key if set incorrectly, so beware) + 'perOwnerSetting' => false, // if set to true this'll make sure only 1 key per 'owner' (potentially multi-key if set incorrectly, so beware) - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ // Invalidates our whole cache. static::reset_mitigation_cache_for_issue_3504(); - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ - $id = (int)$id; + $id = (int) $id; // if owner = -1, add current // Hard -1 for now - settings don't need - if (!isset($owner) || $owner === -1) $owner = zeroBSCRM_user(); @@ -2145,1188 +2429,1358 @@ public function addUpdateSetting($args=array()){ return false; } - // setting ID finder - if obj key provided, check setting not already present (if so overwrite) - // keeps unique... - if ((empty($id) || $id <= 0) - && - (isset($data['key']) && !empty($data['key']))) { + // setting ID finder - if obj key provided, check setting not already present (if so overwrite) + // keeps unique... + if ( ( empty( $id ) || $id <= 0 ) + && + ( isset( $data['key'] ) && ! empty( $data['key'] ) ) ) { - // if perOwnerSetting it's 1 key-ed ret per owner, so query bit diff here: - if (!$perOwnerSetting){ + // if perOwnerSetting it's 1 key-ed ret per owner, so query bit diff here: + if ( ! $perOwnerSetting ) { - // check existence + return ID - $potentialID = (int)$this->getSetting(array( - 'key' => $data['key'], - 'onlyID' => true - )); + // check existence + return ID + $potentialID = (int) $this->getSetting( + array( + 'key' => $data['key'], + 'onlyID' => true, + ) + ); - } else { - - // perownedBy - - // if no owner, return false, cannot be (shouldn't be cos of above) - if ($owner <= 0) return false; - - // check existence + return ID - $potentialID = (int)$this->getSetting(array( - 'key' => $data['key'], - 'onlyID' => true, - 'ownedBy' => $owner - )); - } + } else { - // override empty ID - if (!empty($potentialID) && $potentialID > 0) $id = $potentialID; + // perownedBy - } + // if no owner, return false, cannot be (shouldn't be cos of above) + if ( $owner <= 0 ) { + return false; + } + // check existence + return ID + $potentialID = (int) $this->getSetting( + array( + 'key' => $data['key'], + 'onlyID' => true, + 'ownedBy' => $owner, + ) + ); + } - #} ========= / CHECK FIELDS =========== + // override empty ID + if ( ! empty( $potentialID ) && $potentialID > 0 ) { + $id = $potentialID; + } + } - #} Var up any val (json_encode) - if (in_array(gettype($data['val']),array("object","array"))){ + #} ========= / CHECK FIELDS =========== - // WH note: it was necessary to add JSON_UNESCAPED_SLASHES to properly save down without issue - // combined with a more complex zeroBSCRM_stripSlashes recurrsive - // https://stackoverflow.com/questions/7282755/how-to-remove-backslash-on-json-encode-function - $data['val'] = json_encode($data['val'],JSON_UNESCAPED_SLASHES); + #} Var up any val (json_encode) + if ( in_array( gettype( $data['val'] ), array( 'object', 'array' ) ) ) { - } + // WH note: it was necessary to add JSON_UNESCAPED_SLASHES to properly save down without issue + // combined with a more complex zeroBSCRM_stripSlashes recurrsive + // https://stackoverflow.com/questions/7282755/how-to-remove-backslash-on-json-encode-function + $data['val'] = json_encode( $data['val'], JSON_UNESCAPED_SLASHES ); + } - if (isset($id) && !empty($id) && $id > 0){ + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - //echo 'updating setting id '.$id.'!'; + // echo 'updating setting id '.$id.'!'; - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['settings'], - array( + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['settings'], + array( - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $owner, + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $owner, + + // fields + 'zbsset_key' => $data['key'], + 'zbsset_val' => $data['val'], + 'zbsset_lastupdated' => time(), + ), + array( // where + 'ID' => $id, + ), + array( // field data types + '%d', + '%s', + '%s', + '%d', + ), + array( // where data types + '%d', + ) + ) !== false ) { - // fields - 'zbsset_key' => $data['key'], - 'zbsset_val' => $data['val'], - 'zbsset_lastupdated' => time() - ), - array( // where - 'ID' => $id - ), - array( // field data types - '%d', - '%s', - '%s', - '%d' - ), - array( // where data types - '%d' - )) !== false){ + // Successfully updated - Return id + return $id; - // Successfully updated - Return id - return $id; + } else { - } else { + // FAILED update + return false; - // FAILED update - return false; + } + } else { - } + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['settings'], + array( - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['settings'], - array( + // ownership + 'zbs_site' => zeroBSCRM_site(), + 'zbs_team' => zeroBSCRM_team(), + 'zbs_owner' => $owner, + + // fields + 'zbsset_key' => $data['key'], + 'zbsset_val' => $data['val'], + 'zbsset_created' => time(), + 'zbsset_lastupdated' => time(), + ), + array( // field data types + '%d', // site + '%d', // team + '%d', // owner + + '%s', + '%s', + '%d', + '%d', + ) + ) > 0 ) { - // ownership - 'zbs_site' => zeroBSCRM_site(), - 'zbs_team' => zeroBSCRM_team(), - 'zbs_owner' => $owner, + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + return $newID; - // fields - 'zbsset_key' => $data['key'], - 'zbsset_val' => $data['val'], - 'zbsset_created' => time(), - 'zbsset_lastupdated' => time() - ), - array( // field data types - '%d', // site - '%d', // team - '%d', // owner + } else { - '%s', - '%s', - '%d', - '%d' - ) ) > 0){ + #} Failed to Insert + return false; - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - return $newID; + } + } - } else { + return false; + } - #} Failed to Insert - return false; + /** + * deletes a setting object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteSetting( $args = array() ) { - } + global $ZBSCRM_t, $wpdb; - } + #} ============ LOAD ARGS ============= + $defaultArgs = array( - return false; + 'id' => -1, + 'key' => '', - } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - /** - * deletes a setting object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteSetting($args=array()){ + // if ID passed, Check ID & Delete :) + $id = (int) $id; + if ( $id > 0 ) { + return zeroBSCRM_db2_deleteGeneric( $id, 'settings' ); + } - global $ZBSCRM_t,$wpdb; + // if key, find and delete + if ( ! empty( $key ) ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + $setting_id = $this->getSetting( + array( + 'key' => $key, + 'onlyID' => true, + ) + ); - 'id' => -1, - 'key' => '' + return zeroBSCRM_db2_deleteGeneric( $setting_id, 'settings' ); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + } - // if ID passed, Check ID & Delete :) - $id = (int)$id; - if ( $id > 0) { - return zeroBSCRM_db2_deleteGeneric($id,'settings'); - } + return false; + } - // if key, find and delete - if ( !empty( $key ) ){ - - $setting_id = $this->getSetting( array( 'key' => $key, 'onlyID' => true ) ); - - return zeroBSCRM_db2_deleteGeneric( $setting_id, 'settings' ); - - } + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_setting( $obj = false ) { - return false; + $res = false; - } + if ( isset( $obj->ID ) ) { - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_setting( $obj=false ){ + $res = array(); + $res['id'] = $obj->ID; + $res['key'] = $obj->zbsset_key; + $res['val'] = $this->unpack_setting( $obj->zbsset_val ); + $res['created'] = $obj->zbsset_created; + $res['updated'] = $obj->zbsset_lastupdated; - $res = false; + } - if (isset($obj->ID)){ + return $res; + } + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return string + */ + private function tidy_settingSingular( $obj = false ) { - $res = array(); - $res['id'] = $obj->ID; - $res['key'] = $obj->zbsset_key; - $res['val'] = $this->unpack_setting( $obj->zbsset_val ); - $res['created'] = $obj->zbsset_created; - $res['updated'] = $obj->zbsset_lastupdated; + if ( isset( $obj->ID ) ) { - } + return $this->unpack_setting( $obj->zbsset_val ); - return $res; + } + return false; + } - } + /** + * Takes a setting as db value and attempts to cast it correctly + * + * @param mixed $var (DB value) + * + * @return mixed + */ + private function unpack_setting( $var = false ) { - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return string - */ - private function tidy_settingSingular( $obj=false ){ + if ( $var !== false ) { - if (isset($obj->ID)){ + $value = $this->stripSlashes( $this->decodeIfJSON( $var ) ); - return $this->unpack_setting( $obj->zbsset_val ); + // catch this oddly non-decoded case + if ( $value == '[]' ) { + return array(); + } - } + // if we've a string, check it isn't viably an int + // .. if so, cast as int + if ( is_string( $value ) && jpcrm_is_int( $value ) ) { + $value = (int) $value; + } - return false; + return $value; + } - } + // fallback to returning the value passed + return $var; + } - /** - * Takes a setting as db value and attempts to cast it correctly - * - * @param mixed $var (DB value) - * - * @return mixed - */ - private function unpack_setting( $var=false ){ + // =========== / SETTINGS ======================================================= + // =============================================================================== - if ($var !== false){ + // =============================================================================== + // =========== META ============================================================ - $value = $this->stripSlashes($this->decodeIfJSON($var)); + /** + * Wrapper, use $this->meta($objtype,$objid,$key) for easy retrieval of singular + * Simplifies $this->getMeta + * + * @param int objtype + * @param int objid + * @param string key + * + * @return bool result + */ + public function meta( $objtype = -1, $objid = -1, $key = '', $default = false ) { - // catch this oddly non-decoded case - if ($value == '[]') return array(); + if ( ! empty( $key ) ) { - // if we've a string, check it isn't viably an int - // .. if so, cast as int - if ( is_string($value) && jpcrm_is_int($value) ) $value = (int)$value; + return $this->getMeta( + array( - return $value; - } + 'objtype' => $objtype, + 'objid' => $objid, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, - // fallback to returning the value passed - return $var; + ) + ); - } + } + return $default; + } + /** + * returns full meta line +- details + * + * @param array $args Associative array of arguments + * key, fullDetails, default + * + * @return array result + */ + public function getMeta( $args = array() ) { + #} =========== LOAD ARGS ============== + $defaultArgs = array( - // =========== / SETTINGS ======================================================= - // =============================================================================== + 'objid' => -1, // Object ID + 'objtype' => -1, // Object Type + 'key' => false, // key *Required + 'default' => false, + 'fullDetails' => false, // set this to 1 and get ID|key|val, rather than just the val + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // meta don't need owners yet :) + 'onlyID' => false, // returns scalar ID of line + 'return_all_lines' => false, // if just specifying a key and setting this to true, will return all meta lines with key + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + #} =========== CHECK FIELDS ============= - // =============================================================================== - // =========== META ============================================================ + // check obtype is legit + if ( $objtype !== -1 && $this->objTypeKey( $objtype ) === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + return false; + } + // obj id + $objid = (int) $objid; - /** - * Wrapper, use $this->meta($objtype,$objid,$key) for easy retrieval of singular - * Simplifies $this->getMeta - * - * @param int objtype - * @param int objid - * @param string key - * - * @return bool result - */ - public function meta($objtype=-1,$objid=-1,$key='',$default=false){ + // for now, meta hard ignores owners + $ignoreowner = true; - if (!empty($key)){ + #} =========== / CHECK FIELDS ============= - return $this->getMeta(array( + #} Check key + if ( ! empty( $key ) ) { - 'objtype' => $objtype, - 'objid' => $objid, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - )); + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['meta']; - } + #} ============= WHERE ================ - return $default; - } - - /** - * returns full meta line +- details - * - * @param array $args Associative array of arguments - * key, fullDetails, default - * - * @return array result - */ - public function getMeta($args=array()){ + // Add ID + if ( $objid > 0 ) { + $wheres['zbsm_objid'] = array( 'zbsm_objid', '=', '%d', $objid ); + } + // Add OBJTYPE + if ( $objtype > 0 ) { + $wheres['zbsm_objtype'] = array( 'zbsm_objtype', '=', '%d', $objtype ); + } + // Add KEY + $wheres['zbsm_key'] = array( 'zbsm_key', '=', '%s', $key ); + + #} ============ / WHERE ============== + + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} =========== LOAD ARGS ============== - $defaultArgs = array( + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ); + if ( ! $return_all_lines ) { + $query .= $this->buildPaging( 0, 1 ); + } - 'objid' => -1, // Object ID - 'objtype' => -1, // Object Type - 'key' => false, // key *Required + try { - 'default' => false, + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); - 'fullDetails' => false, // set this to 1 and get ID|key|val, rather than just the val + if ( ! $return_all_lines ) { - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // meta don't need owners yet :) - - 'onlyID' => false, // returns scalar ID of line - 'return_all_lines' => false, // if just specifying a key and setting this to true, will return all meta lines with key + // singular + $result = $wpdb->get_row( $queryObj, OBJECT ); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + } else { - #} =========== CHECK FIELDS ============= + // multi-line + $result = $wpdb->get_results( $queryObj, OBJECT ); - // check obtype is legit - if ( $objtype !== -1 && $this->objTypeKey( $objtype ) === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - return false; - } + } + } catch ( Exception $e ) { - // obj id - $objid = (int)$objid; + #} General SQL Err + $this->catchSQLError( $e ); - // for now, meta hard ignores owners - $ignoreowner = true; + } - #} =========== / CHECK FIELDS ============= - - #} Check key - if (!empty($key)){ + // results + if ( isset( $result ) ) { - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + #} Has results, tidy + return + if ( ! $return_all_lines ) { - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['meta']; + #} Only ID? return it directly + if ( $onlyID === true ) { + return $result->ID; + } - #} ============= WHERE ================ + #} full line or scalar setting val + if ( $fullDetails ) { + return $this->tidy_meta( $result ); + } else { + return $this->tidy_metaSingular( $result ); + } + } else { - // Add ID - if ( $objid > 0 ) { - $wheres['zbsm_objid'] = array('zbsm_objid','=','%d',$objid); - } - // Add OBJTYPE - if ( $objtype > 0 ){ - $wheres['zbsm_objtype'] = array('zbsm_objtype','=','%d',$objtype); - } - // Add KEY - $wheres['zbsm_key'] = array('zbsm_key','=','%s',$key); + // multi-line + $results_array = array(); + foreach ( $result as $index => $meta_line ) { - #} ============ / WHERE ============== + $results_array[] = $this->tidy_meta( $meta_line ); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + } - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + return $results_array; + } + } + } // / if ID - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC'); + return $default; + } - if ( !$return_all_lines ){ - $query .= $this->buildPaging(0,1); - } + /** + * returns FIRST ID which has matching meta keval pair + * + * @param array $args Associative array of arguments + * key, fullDetails, default + * + * @return array result + */ + public function getIDWithMeta( $args = array() ) { + #} =========== LOAD ARGS ============== + $defaultArgs = array( - try { + 'objtype' => -1, // REQ + 'key' => false, // REQ + 'val' => false, // REQ - #} Prep & run query - $queryObj = $this->prepare($query,$params); + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // meta don't need owners yet :) - if ( !$return_all_lines ){ - - // singular - $result = $wpdb->get_row($queryObj, OBJECT); + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - } else { + #} =========== CHECK FIELDS ============= - // multi-line - $result = $wpdb->get_results( $queryObj, OBJECT ); + // check obtype is completed + legit + if ( empty( $objtype ) ) { + return false; + } + if ( $this->objTypeKey( $objtype ) === -1 ) { + return false; + } - } + // meta key + if ( empty( $key ) || empty( $val ) || $key == false || $val == false ) { + return false; + } - } catch (Exception $e){ + // for now, meta hard ignores owners + $ignoreowner = true; - #} General SQL Err - $this->catchSQLError($e); + #} =========== / CHECK FIELDS ============= - } + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - // results - if ( isset( $result ) ){ + #} Build query + $query = 'SELECT zbsm_objid FROM ' . $ZBSCRM_t['meta']; - #} Has results, tidy + return - if ( !$return_all_lines ){ - - #} Only ID? return it directly - if ( $onlyID === true ){ - return $result->ID; - } + #} ============= WHERE ================ - #} full line or scalar setting val - if ( $fullDetails ){ - return $this->tidy_meta( $result ); - } else { - return $this->tidy_metaSingular( $result ); - } + #} Add OBJTYPE + $wheres['zbsm_objtype'] = array( 'zbsm_objtype', '=', '%d', $objtype ); + #} Add KEY + $wheres['zbsm_key'] = array( 'zbsm_key', '=', '%s', $key ); + #} Add VAL + $wheres['zbsm_val'] = array( 'zbsm_val', '=', '%s', $val ); - } else { + #} ============ / WHERE ============== - // multi-line - $results_array = array(); - foreach ( $result as $index => $meta_line ){ + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - $results_array[] = $this->tidy_meta( $meta_line ); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - } + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - return $results_array; - } + try { - } + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $v = (int) $wpdb->get_var( $queryObj ); + if ( $v > -1 ) { + return $v; + } + } catch ( Exception $e ) { - } // / if ID + #} General SQL Err + $this->catchSQLError( $e ); - return $default; + } - } - - /** - * returns FIRST ID which has matching meta keval pair - * - * @param array $args Associative array of arguments - * key, fullDetails, default - * - * @return array result - */ - public function getIDWithMeta($args=array()){ + return -1; + } - #} =========== LOAD ARGS ============== - $defaultArgs = array( + /** + * Wrapper, use $this->updateMeta($objtype,$objid,$key,$val) for easy update of setting + * Uses $this->addUpdateMeta + * ... USE sub-layer rather than this direct, gives a degree of abstraction + * + * @param string key + * @param string value + * + * @return bool result + */ + public function updateMeta( $objtype = -1, $objid = -1, $key = '', $val = '' ) { + if ( ! empty( $key ) ) { // && !empty($val) - 'objtype' => -1, // REQ - 'key' => false, // REQ - 'val' => false, // REQ + return $this->addUpdateMeta( + array( - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // meta don't need owners yet :) + 'data' => array( - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + 'objid' => $objid, + 'objtype' => $objtype, + 'key' => $key, + 'val' => $val, + ), - #} =========== CHECK FIELDS ============= + ) + ); - // check obtype is completed + legit - if ( empty( $objtype ) ) { - return false; } - if ($this->objTypeKey($objtype) === -1) return false; - - // meta key - if (empty($key) || empty($val) || $key == false || $val == false) return false; - - // for now, meta hard ignores owners - $ignoreowner = true; - #} =========== / CHECK FIELDS ============= + return false; + } - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + /** + * adds or updates a setting object + * ... for a quicker wrapper, use $this->updateMeta($key,$val) + * + * @param array $args Associative array of arguments + * id (not req.), owner (not req.) data -> key/val + * + * @return int line ID + */ + public function addUpdateMeta( $args = array() ) { - #} Build query - $query = "SELECT zbsm_objid FROM ".$ZBSCRM_t['meta']; + global $ZBSCRM_t, $wpdb; - #} ============= WHERE ================ + #} ============ LOAD ARGS ============= + $defaultArgs = array( - #} Add OBJTYPE - $wheres['zbsm_objtype'] = array('zbsm_objtype','=','%d',$objtype); - #} Add KEY - $wheres['zbsm_key'] = array('zbsm_key','=','%s',$key); - #} Add VAL - $wheres['zbsm_val'] = array('zbsm_val','=','%s',$val); + 'id' => -1, + // owner HARD disabled for this for now - not req. for each meta + // 'owner' => -1, - #} ============ / WHERE ============== + // fields (directly) + 'data' => array( - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + 'objid' => -1, + 'objtype' => -1, + 'key' => '', + 'val' => '', - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + ), - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ + #} ========== CHECK FIELDS ============ - try { + $id = (int) $id; - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $v = (int)$wpdb->get_var($queryObj); - if ($v > -1) return $v; + // if owner = -1, add current + // if (!isset($owner) || $owner === -1) $owner = zeroBSCRM_user(); + // owner HARD disabled for this for now - not req. for each meta + $owner = -1; - } catch (Exception $e){ + // check key present + legit + if ( empty( $data['key'] ) ) { + return false; + } - #} General SQL Err - $this->catchSQLError($e); + // check obtype is completed + legit + if ( ! isset( $data['objtype'] ) || empty( $data['objtype'] ) ) { + return false; + } + if ( $this->objTypeKey( $data['objtype'] ) === -1 ) { + return false; + } - } + // obj id + $objid = (int) $data['objid']; + if ( empty( $objid ) || $objid < 1 ) { + return false; + } - return -1; + // meta ID finder - if obj key provided, check meta not already present (if so overwrite) + // keeps unique... + if ( ( empty( $id ) || $id <= 0 ) + && + ( isset( $data['key'] ) && ! empty( $data['key'] ) ) + // no need to check obj id + type here, as will return false above if not legit :) + ) { - } + // check existence + return ID + $potentialID = (int) $this->getMeta( + array( + 'objid' => $objid, + 'objtype' => $data['objtype'], + 'key' => $data['key'], + 'onlyID' => true, + ) + ); - /** - * Wrapper, use $this->updateMeta($objtype,$objid,$key,$val) for easy update of setting - * Uses $this->addUpdateMeta - * ... USE sub-layer rather than this direct, gives a degree of abstraction - * - * @param string key - * @param string value - * - * @return bool result - */ - public function updateMeta($objtype=-1,$objid=-1,$key='',$val=''){ + // override empty ID + if ( ! empty( $potentialID ) && $potentialID > 0 ) { + $id = $potentialID; + } + } - if (!empty($key)){ // && !empty($val) + #} ========= / CHECK FIELDS =========== - return $this->addUpdateMeta(array( + #} Var up any val (json_encode) + if ( in_array( gettype( $data['val'] ), array( 'object', 'array' ) ) ) { - 'data' => array( + $data['val'] = json_encode( $data['val'] ); - 'objid' => $objid, - 'objtype' => $objtype, - 'key' => $key, - 'val' => $val - ) + } - )); + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - } + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - return false; - } + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['meta'], + array( - /** - * adds or updates a setting object - * ... for a quicker wrapper, use $this->updateMeta($key,$val) - * - * @param array $args Associative array of arguments - * id (not req.), owner (not req.) data -> key/val - * - * @return int line ID - */ - public function addUpdateMeta($args=array()){ + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $owner, + + // fields + 'zbsm_objtype' => $data['objtype'], + 'zbsm_objid' => $objid, + 'zbsm_key' => $data['key'], + 'zbsm_val' => $data['val'], + 'zbsm_lastupdated' => time(), + ), + array( // where + 'ID' => $id, + ), + array( // field data types + '%d', + '%d', + '%d', + '%s', + '%s', + '%d', + ), + array( // where data types + '%d', + ) + ) !== false ) { - global $ZBSCRM_t,$wpdb; + // Successfully updated - Return id + return $id; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } else { - 'id' => -1, - // owner HARD disabled for this for now - not req. for each meta - //'owner' => -1, + // FAILED update + return false; - // fields (directly) - 'data' => array( + } + } else { - 'objid' => -1, - 'objtype' => -1, - 'key' => '', - 'val' => '', - - ) + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['meta'], + array( - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + // ownership + 'zbs_site' => zeroBSCRM_site(), + 'zbs_team' => zeroBSCRM_team(), + 'zbs_owner' => $owner, + + // fields + 'zbsm_objtype' => $data['objtype'], + 'zbsm_objid' => $objid, + 'zbsm_key' => $data['key'], + 'zbsm_val' => $data['val'], + 'zbsm_created' => time(), + 'zbsm_lastupdated' => time(), + ), + array( // field data types + '%d', // site + '%d', // team + '%d', // owner + + '%d', + '%d', + '%s', + '%s', + '%d', + '%d', + ) + ) > 0 ) { - #} ========== CHECK FIELDS ============ + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + return $newID; - $id = (int)$id; + } else { - // if owner = -1, add current - //if (!isset($owner) || $owner === -1) $owner = zeroBSCRM_user(); - // owner HARD disabled for this for now - not req. for each meta - $owner = -1; + #} Failed to Insert + return false; - // check key present + legit - if ( empty( $data['key'] ) ) { - return false; + } } - // check obtype is completed + legit - if (!isset($data['objtype']) || empty($data['objtype'])) return false; - if ($this->objTypeKey($data['objtype']) === -1) return false; - - // obj id - $objid = (int)$data['objid']; if (empty($objid) || $objid < 1) return false; - - // meta ID finder - if obj key provided, check meta not already present (if so overwrite) - // keeps unique... - if ((empty($id) || $id <= 0) - && - (isset($data['key']) && !empty($data['key'])) - // no need to check obj id + type here, as will return false above if not legit :) - ) { - - // check existence + return ID - $potentialID = (int)$this->getMeta(array( - 'objid' => $objid, - 'objtype' => $data['objtype'], - 'key' => $data['key'], - 'onlyID' => true - )); - - - // override empty ID - if (!empty($potentialID) && $potentialID > 0) $id = $potentialID; - - } - - #} ========= / CHECK FIELDS =========== - - #} Var up any val (json_encode) - if (in_array(gettype($data['val']),array("object","array"))){ - - $data['val'] = json_encode($data['val']); - - } - - - if (isset($id) && !empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['meta'], - array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $owner, - - // fields - 'zbsm_objtype' => $data['objtype'], - 'zbsm_objid' => $objid, - 'zbsm_key' => $data['key'], - 'zbsm_val' => $data['val'], - 'zbsm_lastupdated' => time() - ), - array( // where - 'ID' => $id - ), - array( // field data types - '%d', - '%d', - '%d', - '%s', - '%s', - '%d' - ), - array( // where data types - '%d' - )) !== false){ - - // Successfully updated - Return id - return $id; - - } else { - - // FAILED update - return false; - - } - - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['meta'], - array( - - // ownership - 'zbs_site' => zeroBSCRM_site(), - 'zbs_team' => zeroBSCRM_team(), - 'zbs_owner' => $owner, - - // fields - 'zbsm_objtype' => $data['objtype'], - 'zbsm_objid' => $objid, - 'zbsm_key' => $data['key'], - 'zbsm_val' => $data['val'], - 'zbsm_created' => time(), - 'zbsm_lastupdated' => time() - ), - array( // field data types - '%d', // site - '%d', // team - '%d', // owner - - '%d', - '%d', - '%s', - '%s', - '%d', - '%d' - ) ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - return $newID; - - } else { - - #} Failed to Insert - return false; - - } - - } - - return false; - - } - - /** - * deletes a meta object based on objid + key - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteMeta($args=array()){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'objtype' => -1, - 'objid' => -1, - 'key' => '' - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + return false; + } - #} Check ID, find, & Delete :) - $objtype = (int)$objtype; if (isset($objtype) && $objtype !== -1 && $this->objTypeKey($objtype) === -1) return false; - $objid = (int)$objid; if (empty($objid) || $objid < 1) return false; - if (empty($key)) return false; + /** + * deletes a meta object based on objid + key + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteMeta( $args = array() ) { - #} FIND? - $potentialID = (int)$this->getMeta(array( - 'objid' => $objid, - 'objtype' => $objtype, - 'key' => $key, - 'onlyID' => true - )); + global $ZBSCRM_t, $wpdb; - // override empty ID - if (!empty($potentialID) && $potentialID > 0) { + #} ============ LOAD ARGS ============= + $defaultArgs = array( - return $this->deleteMetaByMetaID(array('id'=>$potentialID)); + 'objtype' => -1, + 'objid' => -1, + 'key' => '', - } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - return false; + #} Check ID, find, & Delete :) + $objtype = (int) $objtype; + if ( isset( $objtype ) && $objtype !== -1 && $this->objTypeKey( $objtype ) === -1 ) { + return false; + } + $objid = (int) $objid; + if ( empty( $objid ) || $objid < 1 ) { + return false; + } + if ( empty( $key ) ) { + return false; + } - } + #} FIND? + $potentialID = (int) $this->getMeta( + array( + 'objid' => $objid, + 'objtype' => $objtype, + 'key' => $key, + 'onlyID' => true, + ) + ); - /** - * deletes a meta object from a meta id - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteMetaByMetaID($args=array()){ + // override empty ID + if ( ! empty( $potentialID ) && $potentialID > 0 ) { - global $ZBSCRM_t,$wpdb; + return $this->deleteMetaByMetaID( array( 'id' => $potentialID ) ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } - 'id' => -1 + return false; + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + /** + * deletes a meta object from a meta id + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteMetaByMetaID( $args = array() ) { - #} Check ID & Delete :) - $id = (int)$id; - return zeroBSCRM_db2_deleteGeneric( $id, 'meta' ); + global $ZBSCRM_t, $wpdb; - } + #} ============ LOAD ARGS ============= + $defaultArgs = array( - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_meta( $obj=false ){ + 'id' => -1, - $res = false; + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - $res['objtype'] = $obj->zbsm_objtype; - $res['objid'] = $obj->zbsm_objid; - $res['key'] = $obj->zbsm_key; - $res['val'] = $this->stripSlashes($obj->zbsm_val); - $res['created'] = $obj->zbsm_created; - $res['updated'] = $obj->zbsm_lastupdated; + #} Check ID & Delete :) + $id = (int) $id; + return zeroBSCRM_db2_deleteGeneric( $id, 'meta' ); + } - } + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_meta( $obj = false ) { - return $res; + $res = false; + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + $res['objtype'] = $obj->zbsm_objtype; + $res['objid'] = $obj->zbsm_objid; + $res['key'] = $obj->zbsm_key; + $res['val'] = $this->stripSlashes( $obj->zbsm_val ); + $res['created'] = $obj->zbsm_created; + $res['updated'] = $obj->zbsm_lastupdated; - } + } - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return string - */ - private function tidy_metaSingular($obj=false){ + return $res; + } - $res = false; + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return string + */ + private function tidy_metaSingular( $obj = false ) { - if (isset($obj->ID)) return $this->stripSlashes($this->decodeIfJSON($obj->zbsm_val)); + $res = false; - return $res; + if ( isset( $obj->ID ) ) { + return $this->stripSlashes( $this->decodeIfJSON( $obj->zbsm_val ) ); + } + return $res; + } - } + // =========== / META =========================================================== + // =============================================================================== - // =========== / META =========================================================== - // =============================================================================== + // =============================================================================== + // =========== TAGS =========================================================== + /** + * returns full tag line +- details + * + * @param int id tag id + * @param array $args Associative array of arguments + * withStats + * + * @return array result + */ + public function getTag( $id = -1, $args = array() ) { + #} =========== LOAD ARGS ============== + $defaultArgs = array( + // Alternative search criteria to ID :) + // .. LEAVE blank if using ID + // objtype + name or slug + 'objtype' => -1, + 'name' => '', + 'slug' => '', + 'withStats' => false, + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // Tags don't need owners yet :) - // =============================================================================== - // =========== TAGS =========================================================== - /** - * returns full tag line +- details - * - * @param int id tag id - * @param array $args Associative array of arguments - * withStats - * - * @return array result - */ - public function getTag($id=-1,$args=array()){ + // returns scalar ID of line + 'onlyID' => false, + 'onlySlug' => false, - #} =========== LOAD ARGS ============== - $defaultArgs = array( + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // Alternative search criteria to ID :) - // .. LEAVE blank if using ID - // objtype + name or slug - 'objtype' => -1, - 'name' => '', - 'slug' => '', + #} ========== CHECK FIELDS ============ - 'withStats' => false, + $id = (int) $id; - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // Tags don't need owners yet :) + // got objtype / name/slug? + // check obtype is legit (if completed) + if ( $objtype !== -1 && $this->objTypeKey( $objtype ) === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - // returns scalar ID of line - 'onlyID' => false, - 'onlySlug' => false, + // if using obj type - check name/slug + if ( empty( $name ) && empty( $slug ) ) { + return false; + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} ========== CHECK FIELDS ============ + // ... else should be good to search - $id = (int)$id; + } - // got objtype / name/slug? + // Tags don't need owners yet :) + $ignoreowner = true; - // check obtype is legit (if completed) - if ( $objtype !== -1 && $this->objTypeKey( $objtype ) === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + #} ========= / CHECK FIELDS =========== - // if using obj type - check name/slug - if (empty($name) && empty($slug)) return false; + #} Check ID or name/type + if ( $id > 0 || $objtype > 0 ) { - // ... else should be good to search + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - } - - // Tags don't need owners yet :) - $ignoreowner = true; + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['tags']; - #} ========= / CHECK FIELDS =========== - - #} Check ID or name/type - if ( $id > 0 || $objtype > 0 ) { + #} ============= WHERE ================ - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + // ID + if ( $id > 0 ) { + $wheres['ID'] = array( 'ID', '=', '%d', $id ); + } - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['tags']; + // Object Type + if ( $objtype > 0 ) { + $wheres['zbstag_objtype'] = array( 'zbstag_objtype', '=', '%d', $objtype ); + } - #} ============= WHERE ================ + // Name + if ( ! empty( $name ) ) { + $wheres['zbstag_name'] = array( 'zbstag_name', '=', '%s', $name ); + } - // ID - if ( $id > 0 ) { - $wheres['ID'] = array( 'ID', '=', '%d', $id ); - } + // Slug + if ( ! empty( $slug ) ) { + $wheres['zbstag_slug'] = array( 'zbstag_slug', '=', '%s', $slug ); + } - // Object Type - if ( $objtype > 0 ) { - $wheres['zbstag_objtype'] = array( 'zbstag_objtype', '=', '%d', $objtype ); - } + #} ============ / WHERE ============== - // Name - if ( ! empty( $name ) ) { - $wheres['zbstag_name'] = array( 'zbstag_name', '=', '%s', $name ); - } + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - // Slug - if ( ! empty( $slug) ) { - $wheres['zbstag_slug'] = array( 'zbstag_slug', '=', '%s', $slug ); - } + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} ============ / WHERE ============== + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + try { - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + } catch ( Exception $e ) { - try { + #} General SQL Err + $this->catchSQLError( $e ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + } - } catch (Exception $e){ + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - #} General SQL Err - $this->catchSQLError($e); + #} Has results, tidy + return - } + #} Only ID? return it directly + if ( $onlyID === true ) { + return $potentialRes->ID; + } - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + #} Only slug? return it directly + if ( $onlySlug === true ) { + return $potentialRes->zbstag_slug; + } - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID === true) return $potentialRes->ID; - - #} Only slug? return it directly - if ($onlySlug === true) return $potentialRes->zbstag_slug; - - // tidy - $res = $this->tidy_tag($potentialRes); + // tidy + $res = $this->tidy_tag( $potentialRes ); // with stats? if ( $withStats ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add all stats lines - $res['stats'] = $this->getTagStats(array('tagid'=>$potentialRes->ID)); - - } + // add all stats lines + $res['stats'] = $this->getTagStats( array( 'tagid' => $potentialRes->ID ) ); + + } - return $res; + return $res; - } + } + } // / if ID - } // / if ID + return false; + } - return false; + /** + * returns tag detail lines + * + * @param array $args Associative array of arguments + * withStats, searchPhrase, sortByField, sortOrder, page, perPage + * + * @return array of tag lines + */ + public function getAllTags( $args = array() ) { - } + #} ============ LOAD ARGS ============= + $defaultArgs = array( - /** - * returns tag detail lines - * - * @param array $args Associative array of arguments - * withStats, searchPhrase, sortByField, sortOrder, page, perPage - * - * @return array of tag lines - */ - public function getAllTags($args=array()){ + 'searchPhrase' => '', + 'withStats' => false, - #} ============ LOAD ARGS ============= - $defaultArgs = array( + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, + 'perPage' => 100, - 'searchPhrase' => '', - 'withStats' => false, + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // Tags don't need owners yet :) - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, - 'perPage' => 100, + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // Tags don't need owners yet :) + // Tags don't need owners yet :) + $ignoreowner = true; - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - // Tags don't need owners yet :) - $ignoreowner = true; + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['tags']; - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + #} ============= WHERE ================ - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['tags']; + #} Add Search phrase + if ( ! empty( $searchPhrase ) ) { - #} ============= WHERE ================ + $wheres['zbstag_name'] = array( 'zbstag_name', 'LIKE', '%s', '%' . $searchPhrase . '%' ); - #} Add Search phrase - if (!empty($searchPhrase)){ + } - $wheres['zbstag_name'] = array('zbstag_name','LIKE','%s','%'.$searchPhrase.'%'); + #} ============ / WHERE =============== - } + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} ============ / WHERE =============== + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Build out any WHERE clauses - $wheresArr= $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + try { - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - try { + } catch ( Exception $e ) { - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} General SQL Err + $this->catchSQLError( $e ); - } catch (Exception $e){ + } - #} General SQL Err - $this->catchSQLError($e); + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - } + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + // tidy + $resArr = $this->tidy_tag( $resDataLine ); - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $resArr = $this->tidy_tag($resDataLine); + // with stats? + if ( isset( $withStats ) && $withStats ) { - // with stats? - if (isset($withStats) && $withStats){ + // add all stats lines + $res['stats'] = $this->getTagStats( array( 'tagid' => $resDataLine->ID ) ); - // add all stats lines - $res['stats'] = $this->getTagStats(array('tagid'=>$resDataLine->ID)); - - } + } - $res[] = $resArr; + $res[] = $resArr; - } - } + } + } - return $res; - } + return $res; + } - /** - * adds or updates a tag object - * - * @param array $args Associative array of arguments - * id (if update), ??? - * - * @return int line ID - */ - public function addUpdateTag($args=array()){ + /** + * adds or updates a tag object + * + * @param array $args Associative array of arguments + * id (if update), ??? + * + * @return int line ID + */ + public function addUpdateTag( $args = array() ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'id' => -1, + 'id' => -1, - // fields (directly) - 'data' => array( + // fields (directly) + 'data' => array( - 'objtype' => -1, - 'name' => '', - 'slug' => '', - // OWNERS will all be set to -1 for tags for now :) - //'owner' => -1 + 'objtype' => -1, + 'name' => '', + 'slug' => '', + // OWNERS will all be set to -1 for tags for now :) + // 'owner' => -1 - ) + ), - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ - $id = (int)$id; + $id = (int) $id; // check obtype is completed + legit if ( empty( $data['objtype'] ) ) { return false; } - if ($this->objTypeKey($data['objtype']) === -1) return false; - - // if owner = -1, add current - // tags don't really need this level of ownership - // so leaving as -1 for now :) - //if (!isset($data['owner']) || $data['owner'] === -1) $data['owner'] = zeroBSCRM_user(); - $data['owner'] = -1; + if ( $this->objTypeKey( $data['objtype'] ) === -1 ) { + return false; + } - // check name present + legit - if (!isset($data['name']) || empty($data['name'])) return false; + // if owner = -1, add current + // tags don't really need this level of ownership + // so leaving as -1 for now :) + // if (!isset($data['owner']) || $data['owner'] === -1) $data['owner'] = zeroBSCRM_user(); + $data['owner'] = -1; + + // check name present + legit + if ( ! isset( $data['name'] ) || empty( $data['name'] ) ) { + return false; + } if ( empty( $data['slug'] ) ) { $potential_slug = sanitize_key( $data['name'] ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable @@ -3344,507 +3798,588 @@ public function addUpdateTag($args=array()){ } } - // tag ID finder - if obj name provided, check tag not already present (if so overwrite) - // keeps unique... - if ((empty($id) || $id <= 0) - && - ( - (isset($data['name']) && !empty($data['name'])) || - (isset($data['slug']) && !empty($data['slug'])) - )) { - - // check by slug - // check existence + return ID - $potentialID = (int)$this->getTag(-1,array( - 'objtype' => $data['objtype'], - 'slug' => $data['slug'], - 'onlyID' => true - )); - - // override empty ID - if (!empty($potentialID) && $potentialID > 0) $id = $potentialID; - - } - - #} ========= / CHECK FIELDS =========== - - #} Check if ID present - $id = (int)$id; - if (!empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['tags'], - array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $data['owner'], - - // fields - 'zbstag_objtype' => $data['objtype'], - 'zbstag_name' => $data['name'], - 'zbstag_slug' => $data['slug'], - 'zbstag_lastupdated' => time() - ), - array( // where - 'ID' => $id - ), - array( // field data types - '%d', - '%d', - '%s', - '%s', - '%d' - ), - array( // where data types - '%d' - )) !== false){ - - // Successfully updated - Return id - return $id; - - } else { - - // FAILED update - return false; - - } - - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['tags'], - array( - - // ownership - 'zbs_site' => zeroBSCRM_site(), - 'zbs_team' => zeroBSCRM_team(), - 'zbs_owner' => $data['owner'], - - // fields - 'zbstag_objtype' => $data['objtype'], - 'zbstag_name' => $data['name'], - 'zbstag_slug' => $data['slug'], - 'zbstag_created' => time(), - 'zbstag_lastupdated' => time() - ), - array( // field data types - '%d', // site - '%d', // team - '%d', // owner - - '%d', - '%s', - '%s', - '%d', - '%d' - ) ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - return $newID; - - } else { - - #} Failed to Insert - return false; - - } - - } - - return false; + // tag ID finder - if obj name provided, check tag not already present (if so overwrite) + // keeps unique... + if ( ( empty( $id ) || $id <= 0 ) + && + ( + ( isset( $data['name'] ) && ! empty( $data['name'] ) ) || + ( isset( $data['slug'] ) && ! empty( $data['slug'] ) ) + ) ) { + + // check by slug + // check existence + return ID + $potentialID = (int) $this->getTag( + -1, + array( + 'objtype' => $data['objtype'], + 'slug' => $data['slug'], + 'onlyID' => true, + ) + ); + + // override empty ID + if ( ! empty( $potentialID ) && $potentialID > 0 ) { + $id = $potentialID; + } + } + + #} ========= / CHECK FIELDS =========== + + #} Check if ID present + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) + + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['tags'], + array( + + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $data['owner'], + + // fields + 'zbstag_objtype' => $data['objtype'], + 'zbstag_name' => $data['name'], + 'zbstag_slug' => $data['slug'], + 'zbstag_lastupdated' => time(), + ), + array( // where + 'ID' => $id, + ), + array( // field data types + '%d', + '%d', + '%s', + '%s', + '%d', + ), + array( // where data types + '%d', + ) + ) !== false ) { + + // Successfully updated - Return id + return $id; + + } else { + + // FAILED update + return false; + + } + } else { + + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['tags'], + array( + + // ownership + 'zbs_site' => zeroBSCRM_site(), + 'zbs_team' => zeroBSCRM_team(), + 'zbs_owner' => $data['owner'], + + // fields + 'zbstag_objtype' => $data['objtype'], + 'zbstag_name' => $data['name'], + 'zbstag_slug' => $data['slug'], + 'zbstag_created' => time(), + 'zbstag_lastupdated' => time(), + ), + array( // field data types + '%d', // site + '%d', // team + '%d', // owner + + '%d', + '%s', + '%s', + '%d', + '%d', + ) + ) > 0 ) { + + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + return $newID; + + } else { + + #} Failed to Insert + return false; + + } + } + + return false; + } + + /** + * adds or updates any object's tags + * ... this is really just a wrapper for addUpdateTagObjLinks + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateObjectTags( $args = array() ) { + + global $ZBSCRM_t, $wpdb; - } - - /** - * adds or updates any object's tags - * ... this is really just a wrapper for addUpdateTagObjLinks - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateObjectTags($args=array()){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'objid' => -1, // REQ - 'objtype' => -1, // REQ - - // generic pass-through (array of tag strings or tag IDs): - 'tag_input' => -1, - - // or either specific: - 'tagIDs' => -1, - 'tags' => -1, - - 'mode' => 'replace' - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'objid' => -1, // REQ + 'objtype' => -1, // REQ + + // generic pass-through (array of tag strings or tag IDs): + 'tag_input' => -1, + + // or either specific: + 'tagIDs' => -1, + 'tags' => -1, + + 'mode' => 'replace', + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ - // check id - $objid = (int)$objid; if (empty($objid) || $objid <= 0) return false; + // check id + $objid = (int) $objid; + if ( empty( $objid ) || $objid <= 0 ) { + return false; + } // check obtype is legit (if completed) if ( $objtype === -1 || $this->objTypeKey( $objtype ) === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable return false; } - #} ========= / CHECK FIELDS =========== + #} ========= / CHECK FIELDS =========== - // If passed tag_input, infer if using ID's or tags - if ( is_array($tag_input)){ + // If passed tag_input, infer if using ID's or tags + if ( is_array( $tag_input ) ) { - // assume ID's - $tagIDs = $tag_input; + // assume ID's + $tagIDs = $tag_input; - // got strings? - foreach ( $tag_input as $tag ){ + // got strings? + foreach ( $tag_input as $tag ) { - // if it's not an int, we can assume it's a string - if ( !jpcrm_is_int($tag) ){ + // if it's not an int, we can assume it's a string + if ( ! jpcrm_is_int( $tag ) ) { - // process as strings (tags) - $tagIDs = -1; - $tags = $tag_input; - break; - - } - - } + // process as strings (tags) + $tagIDs = -1; + $tags = $tag_input; + break; - } + } + } + } // If using tags, convert these to ids :) // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. if ( is_array( $tags ) ) { - // overwrite - $tagIDs = array(); - - // cycle through + find - foreach ($tags as $tag){ + // overwrite + $tagIDs = array(); - $tagID = $this->getTag(-1,array( - 'objtype' => $objtype, - 'name' => $tag, - 'onlyID' => true - )); - - //echo 'looking for tag "'.$tag.'" got id '.$tagID.'!
'; + // cycle through + find + foreach ( $tags as $tag ) { - if (!empty($tagID)) - $tagIDs[] = $tagID; - else { - - //create - $tagID = $this->addUpdateTag(array( - 'data'=>array( - 'objtype' => $objtype, - 'name' => $tag))); - //add - if (!empty($tagID)) $tagIDs[] = $tagID; + $tagID = $this->getTag( + -1, + array( + 'objtype' => $objtype, + 'name' => $tag, + 'onlyID' => true, + ) + ); - } - } + // echo 'looking for tag "'.$tag.'" got id '.$tagID.'!
'; - } - - return $this->addUpdateTagObjLinks(array( - 'objtype' =>$objtype, - 'objid' =>$objid, - 'tagIDs' =>$tagIDs, - 'mode' =>$mode)); + if ( ! empty( $tagID ) ) { + $tagIDs[] = $tagID; + } else { - } + // create + $tagID = $this->addUpdateTag( + array( + 'data' => array( + 'objtype' => $objtype, + 'name' => $tag, + ), + ) + ); + // add + if ( ! empty( $tagID ) ) { + $tagIDs[] = $tagID; + } + } + } + } - /** - * deletes a tag object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteTag($args=array()){ + return $this->addUpdateTagObjLinks( + array( + 'objtype' => $objtype, + 'objid' => $objid, + 'tagIDs' => $tagIDs, + 'mode' => $mode, + ) + ); + } - global $ZBSCRM_t,$wpdb; + /** + * deletes a tag object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteTag( $args = array() ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + global $ZBSCRM_t, $wpdb; - 'id' => -1, - 'deleteLinks' => true + #} ============ LOAD ARGS ============= + $defaultArgs = array( - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + 'id' => -1, + 'deleteLinks' => true, - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - $deleted = zeroBSCRM_db2_deleteGeneric($id,'tags'); + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - // if links, also delete them! - if ($deleteLinks){ + $deleted = zeroBSCRM_db2_deleteGeneric( $id, 'tags' ); - $deletedLinks = $wpdb->delete( - $ZBSCRM_t['taglinks'], - array( // where - 'zbstl_tagid' => $id - ), - array( - '%d' - ) - ); - } + // if links, also delete them! + if ( $deleteLinks ) { - return $deleted; + $deletedLinks = $wpdb->delete( + $ZBSCRM_t['taglinks'], + array( // where + 'zbstl_tagid' => $id, + ), + array( + '%d', + ) + ); + } - } + return $deleted; - return false; + } - } + return false; + } - /** - * retrieves stats for tag (how many contacts/obj's use this tag) (effectively counts tag links split per obj) - * - * @param array $args Associative array of arguments - * id - * - * @return array - */ - public function getAllTagStats($args=array()){ + /** + * retrieves stats for tag (how many contacts/obj's use this tag) (effectively counts tag links split per obj) + * + * @param array $args Associative array of arguments + * id + * + * @return array + */ + public function getAllTagStats( $args = array() ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'id' => -1, - 'owner' => -1, + 'id' => -1, + 'owner' => -1, - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // Tags don't need owners yet :) + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // Tags don't need owners yet :) - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - $ignoreowner = true; + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} Check ID - $id = (int)$id; - if (!empty($id) && $id > 0){ + $ignoreowner = true; - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + #} Check ID + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - #} Build query - $query = "SELECT COUNT(zbstl_objid) c, zbstl_objtype FROM ".$ZBSCRM_t['taglinks']; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} ============= WHERE ================ + #} Build query + $query = 'SELECT COUNT(zbstl_objid) c, zbstl_objtype FROM ' . $ZBSCRM_t['taglinks']; - #} Add ID - $wheres['zbstl_tagid'] = array('zbstl_tagid','=','%d',$id); + #} ============= WHERE ================ + #} Add ID + $wheres['zbstl_tagid'] = array( 'zbstl_tagid', '=', '%d', $id ); // If 'owner' is set then have to ignore owner, because can't do both if ( $owner > 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - // stops ownership check - $ignoreowner = true; + // stops ownership check + $ignoreowner = true; + + // adds owner to query + $wheres['zbs_owner'] = array( 'zbs_owner', '=', '%d', $owner ); - // adds owner to query - $wheres['zbs_owner'] = array('zbs_owner','=','%d',$owner); + } - } + #} ============ / WHERE ============== - #} ============ / WHERE ============== + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} ============ CUSTOM GROUP/ORDERBY ============== - #} ============ CUSTOM GROUP/ORDERBY ============== - - // this allows grouping :) - $orderByCustom = ' GROUP BY zbstl_objtype ORDER BY c ASC'; + // this allows grouping :) + $orderByCustom = ' GROUP BY zbstl_objtype ORDER BY c ASC'; - #} ============ / CUSTOM GROUP/ORDERBY ============ + #} ============ / CUSTOM GROUP/ORDERBY ============ - #} Append to sql (and use our custom order by etc.) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $orderByCustom; + #} Append to sql (and use our custom order by etc.) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $orderByCustom; - try { + try { - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - } catch (Exception $e){ + } catch ( Exception $e ) { - #} General SQL Err - $this->catchSQLError($e); + #} General SQL Err + $this->catchSQLError( $e ); - } + } - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $res[] = $this->tidy_tagstat($resDataLine); + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - } - } + // tidy + $res[] = $this->tidy_tagstat( $resDataLine ); - return $res; + } + } - } // / if ID + return $res; - return false; + } // / if ID - } + return false; + } - /** - * retrieves stats for tag (how many contacts/obj's use this tag) - * this version returns specific count of uses for an objtypeid - * - * @param array $args Associative array of arguments - * id - * - * @return array - */ - public function getTagObjStats($args=array()){ + /** + * retrieves stats for tag (how many contacts/obj's use this tag) + * this version returns specific count of uses for an objtypeid + * + * @param array $args Associative array of arguments + * id + * + * @return array + */ + public function getTagObjStats( $args = array() ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'id' => -1, - 'objtypeid' => -1, - 'owner' => -1, + 'id' => -1, + 'objtypeid' => -1, + 'owner' => -1, - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // Tags don't need owners yet :) + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // Tags don't need owners yet :) - // returns scalar ID of line - 'onlyID' => false + // returns scalar ID of line + 'onlyID' => false, - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - $ignoreowner = true; + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} Check ID - $id = (int)$id; - if (!empty($id) && $id > 0){ + $ignoreowner = true; - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + #} Check ID + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - #} Build query - $query = "SELECT COUNT(zbstl_objid) c, zbstl_objtype FROM ".$ZBSCRM_t['taglinks']; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} ============= WHERE ================ + #} Build query + $query = 'SELECT COUNT(zbstl_objid) c, zbstl_objtype FROM ' . $ZBSCRM_t['taglinks']; - #} Add ID - $wheres['zbstl_tagid'] = array('zbstl_tagid','=','%d',$id); + #} ============= WHERE ================ - #} Adds a specific type id - if (!empty($objtypeid)){ + #} Add ID + $wheres['zbstl_tagid'] = array( 'zbstl_tagid', '=', '%d', $id ); - $wheres['zbstl_objtype'] = array('zbstl_objtype','=','%d',$objtypeid); + #} Adds a specific type id + if ( ! empty( $objtypeid ) ) { - } + $wheres['zbstl_objtype'] = array( 'zbstl_objtype', '=', '%d', $objtypeid ); + } // If 'owner' is set then have to ignore owner, because can't do both if ( $owner > 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - // stops ownership check - $ignoreowner = true; + // stops ownership check + $ignoreowner = true; - // adds owner to query - $wheres['zbs_owner'] = array('zbs_owner','=','%d',$owner); + // adds owner to query + $wheres['zbs_owner'] = array( 'zbs_owner', '=', '%d', $owner ); - } + } - #} ============ / WHERE ============== + #} ============ / WHERE ============== - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - #} ============ CUSTOM GROUP/ORDERBY ============== - - // this allows grouping :) - $orderByCustom = ' GROUP BY zbstl_objtype ORDER BY c ASC LIMIT 0,1'; + #} ============ CUSTOM GROUP/ORDERBY ============== - #} ============ / CUSTOM GROUP/ORDERBY ============ + // this allows grouping :) + $orderByCustom = ' GROUP BY zbstl_objtype ORDER BY c ASC LIMIT 0,1'; - #} Append to sql (and use our custom order by etc.) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $orderByCustom; + #} ============ / CUSTOM GROUP/ORDERBY ============ - try { + #} Append to sql (and use our custom order by etc.) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $orderByCustom; - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + try { - } catch (Exception $e){ + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - #} General SQL Err - $this->catchSQLError($e); + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { - - #} Only ID? return it directly - if ($onlyID === true) return $potentialRes->ID; + } - #} Has results, tidy + return - return $this->tidy_tagstat($potentialRes); + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - } + #} Only ID? return it directly + if ( $onlyID === true ) { + return $potentialRes->ID; + } - } // / if ID + #} Has results, tidy + return + return $this->tidy_tagstat( $potentialRes ); - return false; + } + } // / if ID - } + return false; + } /** * Checks if a tag slug exists @@ -3901,650 +4436,758 @@ public function get_new_tag_slug( int $obj_type_id, string $slug, bool $force_it return $slug_base . $next_slug_iteration; } - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_tag($obj=false){ - - $res = false; - - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ - - $res['objtype'] = $obj->zbstag_objtype; - $res['name'] = $this->stripSlashes($obj->zbstag_name); - $res['slug'] = $obj->zbstag_slug; - - - $res['created'] = $obj->zbstag_created; - $res['lastupdated'] = $obj->zbstag_lastupdated; - - } - - return $res; - - - } - - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_tagstat($obj=false){ - - $res = false; - - if (isset($obj->ID)){ - $res = array(); - $res['count'] = $obj->c; - $res['objtypeid'] = $obj->zbstl_objtype; - $res['objtype'] = $this->objTypeKey($obj->zbstl_objtype); - - } - - return $res; - - - } - - // =========== / TAGS ======================================================= - // =============================================================================== - + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_tag( $obj = false ) { + $res = false; + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + $res['objtype'] = $obj->zbstag_objtype; + $res['name'] = $this->stripSlashes( $obj->zbstag_name ); + $res['slug'] = $obj->zbstag_slug; - // =============================================================================== - // =========== TAG LINKS ======================================================= - /** - * returns tags against an obj type (e.g. contact tags) - * - * @param array $args Associative array of arguments - * objtypeid - * - * @return array result - */ - public function getTagsForObjType($args=array()){ + $res['created'] = $obj->zbstag_created; + $res['lastupdated'] = $obj->zbstag_lastupdated; - #} =========== LOAD ARGS ============== - $defaultArgs = array( + } - 'objtypeid' => -1, + return $res; + } - // select - 'excludeEmpty' => -1, - 'excludeIDs' => -1, // if is an array of tag id's will exclude these :) + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_tagstat( $obj = false ) { - // with - 'withCount' => -1, - - // sort - 'sortByField' => 'zbstag_name', - 'sortOrder' => 'ASC', + $res = false; - 'page' => 0, // this is what page it is (gets * by for limit) - 'perPage' => 10000 + if ( isset( $obj->ID ) ) { + $res = array(); + $res['count'] = $obj->c; + $res['objtypeid'] = $obj->zbstl_objtype; + $res['objtype'] = $this->objTypeKey( $obj->zbstl_objtype ); - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // Tags don't need owners yet :) + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - $ignoreowner = true; + return $res; + } - #} Check ID - $objtypeid = (int)$objtypeid; - if (!empty($objtypeid) && $objtypeid > 0){ + // =========== / TAGS ======================================================= + // =============================================================================== - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + // =============================================================================== + // =========== TAG LINKS ======================================================= + /** + * returns tags against an obj type (e.g. contact tags) + * + * @param array $args Associative array of arguments + * objtypeid + * + * @return array result + */ + public function getTagsForObjType( $args = array() ) { + #} =========== LOAD ARGS ============== + $defaultArgs = array( - #} ============ EXTRA SELECT ============== + 'objtypeid' => -1, - $extraSelect = ''; + // select + 'excludeEmpty' => -1, + 'excludeIDs' => -1, // if is an array of tag id's will exclude these :) - if ($withCount !== -1 || $excludeEmpty !== -1) { + // with + 'withCount' => -1, - // could make this distinct zbstl_objid if need more precision - // NOTE! Ownership leak here - this'll count GLOBALLY! todo: add ownership into this subquery - $extraSelect = ',(SELECT COUNT(taglink.ID) FROM '.$ZBSCRM_t['taglinks'].' taglink WHERE zbstl_tagid = tags.ID AND zbstl_objtype = %d) tagcount'; - $params[] = $objtypeid; + // sort + 'sortByField' => 'zbstag_name', + 'sortOrder' => 'ASC', - } + 'page' => 0, // this is what page it is (gets * by for limit) + 'perPage' => 10000, - #} ============ / EXTRA SELECT ============== + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // Tags don't need owners yet :) - #} Build query - $query = "SELECT tags.*".$extraSelect." FROM ".$ZBSCRM_t['tags'].' tags'; + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - #} ============= WHERE ================ - - // type id - $wheres['zbstag_objtype'] = array('zbstag_objtype','=','%d',$objtypeid); + $ignoreowner = true; - // if exclude empty - if ($excludeEmpty){ - $wheres['direct'][] = array('(SELECT COUNT(taglink.ID) FROM '.$ZBSCRM_t['taglinks'].' taglink WHERE zbstl_tagid = tags.ID AND zbstl_objtype = %d) > 0',array($objtypeid)); + #} Check ID + $objtypeid = (int) $objtypeid; + if ( ! empty( $objtypeid ) && $objtypeid > 0 ) { - } + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - if (is_array($excludeIDs)){ + #} ============ EXTRA SELECT ============== - $checkedExcludedIDs = array(); - foreach ($excludeIDs as $potentialID){ - $pID = (int)$potentialID; - if ($pID > 0 && !in_array($pID, $checkedExcludedIDs)) $checkedExcludedIDs[] = $pID; - } + $extraSelect = ''; - if (count($checkedExcludedIDs) > 0){ + if ( $withCount !== -1 || $excludeEmpty !== -1 ) { - // add exclude ids query part (okay to directly inject here, as validated ints above.) - $wheres['excludedids'] = array('ID','NOT IN','('.implode(',', $checkedExcludedIDs).')'); + // could make this distinct zbstl_objid if need more precision + // NOTE! Ownership leak here - this'll count GLOBALLY! todo: add ownership into this subquery + $extraSelect = ',(SELECT COUNT(taglink.ID) FROM ' . $ZBSCRM_t['taglinks'] . ' taglink WHERE zbstl_tagid = tags.ID AND zbstl_objtype = %d) tagcount'; + $params[] = $objtypeid; - } - } + } - #} ============ / WHERE ============== + #} ============ / EXTRA SELECT ============== - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build query + $query = 'SELECT tags.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['tags'] . ' tags'; - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} ============= WHERE ================ - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); + // type id + $wheres['zbstag_objtype'] = array( 'zbstag_objtype', '=', '%d', $objtypeid ); - try { + // if exclude empty + if ( $excludeEmpty ) { + $wheres['direct'][] = array( '(SELECT COUNT(taglink.ID) FROM ' . $ZBSCRM_t['taglinks'] . ' taglink WHERE zbstl_tagid = tags.ID AND zbstl_objtype = %d) > 0', array( $objtypeid ) ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + } - } catch (Exception $e){ + if ( is_array( $excludeIDs ) ) { - #} General SQL Err - $this->catchSQLError($e); + $checkedExcludedIDs = array(); + foreach ( $excludeIDs as $potentialID ) { + $pID = (int) $potentialID; + if ( $pID > 0 && ! in_array( $pID, $checkedExcludedIDs ) ) { + $checkedExcludedIDs[] = $pID; + } + } - } + if ( count( $checkedExcludedIDs ) > 0 ) { - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + // add exclude ids query part (okay to directly inject here, as validated ints above.) + $wheres['excludedids'] = array( 'ID', 'NOT IN', '(' . implode( ',', $checkedExcludedIDs ) . ')' ); - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $resArr = $this->tidy_tag($resDataLine); + } + } - if ($withCount !== -1){ + #} ============ / WHERE ============== - if (isset($resDataLine->tagcount)) - $resArr['count'] = $resDataLine->tagcount; - else - $resArr['count'] = -1; + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - } + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - $res[] = $resArr; + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - } - } + try { - return $res; + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - } // / if ID + } catch ( Exception $e ) { - return false; + #} General SQL Err + $this->catchSQLError( $e ); - } - /** - * returns tags against an obj (e.g. contact id 101) - * - * @param array $args Associative array of arguments - * objtypeid, objid - * - * @return array result - */ - public function getTagsForObjID($args=array()){ + } - #} =========== LOAD ARGS ============== - $defaultArgs = array( + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - 'objtypeid' => -1, - 'objid' => -1, + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - // with - 'withCount' => -1, - 'onlyID' => -1, + // tidy + $resArr = $this->tidy_tag( $resDataLine ); - // permissions - //'ignoreowner' => false // this'll let you not-check the owner of obj - // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site - // Tags don't need owners yet :) + if ( $withCount !== -1 ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - $ignoreowner = true; - - #} Check ID - $objtypeid = (int)$objtypeid; $objid = (int)$objid; - if (!empty($objtypeid) && $objtypeid > 0 && !empty($objid) && $objid > 0){ + if ( isset( $resDataLine->tagcount ) ) { + $resArr['count'] = $resDataLine->tagcount; + } else { + $resArr['count'] = -1; + } + } - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + $res[] = $resArr; - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['tags']; + } + } - #} ============= WHERE ================ + return $res; - #} Add ID - // rather than using the $wheres, here we have to manually add, because sub queries don't work otherwise. - $whereStr = ' WHERE ID in (SELECT zbstl_tagid FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = %d)'; - $params[] = $objtypeid; $params[] = $objid; + } // / if ID - #} ============ / WHERE ============== + return false; + } + /** + * returns tags against an obj (e.g. contact id 101) + * + * @param array $args Associative array of arguments + * objtypeid, objid + * + * @return array result + */ + public function getTagsForObjID( $args = array() ) { - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} =========== LOAD ARGS ============== + $defaultArgs = array( - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + 'objtypeid' => -1, + 'objid' => -1, - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,10000); - //echo $query; print_r($params); + // with + 'withCount' => -1, + 'onlyID' => -1, - try { + // permissions + // 'ignoreowner' => false // this'll let you not-check the owner of obj + // NOTE 'owner' will ALWAYS be ignored by this, but allows for team/site + // Tags don't need owners yet :) - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + $ignoreowner = true; + + #} Check ID + $objtypeid = (int) $objtypeid; + $objid = (int) $objid; + if ( ! empty( $objtypeid ) && $objtypeid > 0 && ! empty( $objid ) && $objid > 0 ) { + + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['tags']; + + #} ============= WHERE ================ + + #} Add ID + // rather than using the $wheres, here we have to manually add, because sub queries don't work otherwise. + $whereStr = ' WHERE ID in (SELECT zbstl_tagid FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = %d)'; + $params[] = $objtypeid; + $params[] = $objid; + + #} ============ / WHERE ============== + + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - } catch (Exception $e){ + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 10000 ); + // echo $query; print_r($params); - #} General SQL Err - $this->catchSQLError($e); + try { - } + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + } catch ( Exception $e ) { - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - + #} General SQL Err + $this->catchSQLError( $e ); - #} Only ID? return it directly - if ($onlyID === true) - $resObj = $resDataLine->ID; - else - // tidy - $resObj = $this->tidy_tag($resDataLine); + } - if ($withCount){ + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - } + #} Only ID? return it directly + if ( $onlyID === true ) { + $resObj = $resDataLine->ID; + } else { // tidy + $resObj = $this->tidy_tag( $resDataLine ); + } - $res[] = $resObj; + if ( $withCount ) { - } - } + } - return $res; + $res[] = $resObj; - } // / if ID + } + } - return false; + return $res; - } + } // / if ID + return false; + } - /** - * adds or updates a tag link object - * this says "match tag X with obj Y" (effectively 'tagging' it) - * NOTE: DO NOT CALL DIRECTLY, ALWAYS use addUpdateTagObjLinks (or it's wrappers) - because those fire actions :) - * - * @param array $args Associative array of arguments - * id (if update - probably never used here), data(objtype,objid,tagid) - * - * @return int line ID - */ - public function addUpdateTagObjLink($args=array()){ + /** + * adds or updates a tag link object + * this says "match tag X with obj Y" (effectively 'tagging' it) + * NOTE: DO NOT CALL DIRECTLY, ALWAYS use addUpdateTagObjLinks (or it's wrappers) - because those fire actions :) + * + * @param array $args Associative array of arguments + * id (if update - probably never used here), data(objtype,objid,tagid) + * + * @return int line ID + */ + public function addUpdateTagObjLink( $args = array() ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'id' => -1, - 'owner' => -1, + 'id' => -1, + 'owner' => -1, - // fields (directly) - 'data' => array( + // fields (directly) + 'data' => array( - 'objtype' => -1, - 'objid' => -1, - 'tagid' => -1 + 'objtype' => -1, + 'objid' => -1, + 'tagid' => -1, - ) + ), - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ // check obtype is completed + legit if ( empty( $data['objtype'] ) ) { return false; } - if ($this->objTypeKey($data['objtype']) === -1) return false; + if ( $this->objTypeKey( $data['objtype'] ) === -1 ) { + return false; + } // if owner = -1, add current if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable $owner = zeroBSCRM_user(); } - $objid = (int)$data['objid']; $tagid = (int)$data['tagid']; - if (empty($data['objid']) || $data['objid'] < 1 || empty($data['tagid']) || $data['tagid'] < 1) return false; - - #} ========= / CHECK FIELDS =========== - - #} Check if ID present - $id = (int)$id; - if (!empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['taglinks'], - array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $owner, - - // fields - 'zbstl_objtype' => $data['objtype'], - 'zbstl_objid' => $data['objid'], - 'zbstl_tagid' => $data['tagid'] - ), - array( // where - 'ID' => $id - ), - array( // field data types - '%d', - '%d', - '%d', - '%d' - ), - array( // where data types - '%d' - )) !== false){ - - // Successfully updated - Return id - return $id; + $objid = (int) $data['objid']; + $tagid = (int) $data['tagid']; + if ( empty( $data['objid'] ) || $data['objid'] < 1 || empty( $data['tagid'] ) || $data['tagid'] < 1 ) { + return false; + } - } else { + #} ========= / CHECK FIELDS =========== - // FAILED update - return false; + #} Check if ID present + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - } + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['taglinks'], - array( + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['taglinks'], + array( - // ownership - 'zbs_site' => zeroBSCRM_site(), - 'zbs_team' => zeroBSCRM_team(), - 'zbs_owner' => $owner, + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $owner, + + // fields + 'zbstl_objtype' => $data['objtype'], + 'zbstl_objid' => $data['objid'], + 'zbstl_tagid' => $data['tagid'], + ), + array( // where + 'ID' => $id, + ), + array( // field data types + '%d', + '%d', + '%d', + '%d', + ), + array( // where data types + '%d', + ) + ) !== false ) { - // fields - 'zbstl_objtype' => $data['objtype'], - 'zbstl_objid' => $data['objid'], - 'zbstl_tagid' => $data['tagid'] - ), - array( // field data types - '%d', // site - '%d', // team - '%d', // owner + // Successfully updated - Return id + return $id; - '%d', - '%d', - '%d' - ) ) > 0){ + } else { - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - return $newID; + // FAILED update + return false; - } else { + } + } else { - #} Failed to Insert - return false; + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['taglinks'], + array( - } + // ownership + 'zbs_site' => zeroBSCRM_site(), + 'zbs_team' => zeroBSCRM_team(), + 'zbs_owner' => $owner, + + // fields + 'zbstl_objtype' => $data['objtype'], + 'zbstl_objid' => $data['objid'], + 'zbstl_tagid' => $data['tagid'], + ), + array( // field data types + '%d', // site + '%d', // team + '%d', // owner + + '%d', + '%d', + '%d', + ) + ) > 0 ) { - } + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + return $newID; - return false; + } else { - } + #} Failed to Insert + return false; + } + } - /** - * adds or updates tag link objects against an obj - * this says "match tag X,Y,Z with obj Y" (effectively 'tagging' it) - * - * @param array $args Associative array of arguments - * objtype,objid,tags (array of tagids) - * - * @return array $tags - */ - public function addUpdateTagObjLinks($args=array()){ + return false; + } - global $ZBSCRM_t,$wpdb; + /** + * adds or updates tag link objects against an obj + * this says "match tag X,Y,Z with obj Y" (effectively 'tagging' it) + * + * @param array $args Associative array of arguments + * objtype,objid,tags (array of tagids) + * + * @return array $tags + */ + public function addUpdateTagObjLinks( $args = array() ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + global $ZBSCRM_t, $wpdb; - 'owner' => -1, + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'objtype' => -1, - 'objid' => -1, - 'tagIDs' => -1, // array of tag ID's + 'owner' => -1, - 'mode' => 'replace' // replace|append|remove + 'objtype' => -1, + 'objid' => -1, + 'tagIDs' => -1, // array of tag ID's - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + 'mode' => 'replace', // replace|append|remove + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ // check obtype is completed + legit if ( empty( $objtype ) ) { return false; } - if ($this->objTypeKey($objtype) === -1) return false; + if ( $this->objTypeKey( $objtype ) === -1 ) { + return false; + } // if owner = -1, add current if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable $owner = zeroBSCRM_user(); } - // tagging id - $objid = (int)$objid; if (empty($objid) || $objid < 1) return false; + // tagging id + $objid = (int) $objid; + if ( empty( $objid ) || $objid < 1 ) { + return false; + } - // tag list - if (!is_array($tagIDs)) return false; + // tag list + if ( ! is_array( $tagIDs ) ) { + return false; + } - // mode - if (gettype($mode) != 'string' || !in_array($mode, array('replace','append','remove'))) return false; + // mode + if ( gettype( $mode ) != 'string' || ! in_array( $mode, array( 'replace', 'append', 'remove' ) ) ) { + return false; + } - #} ========= / CHECK FIELDS =========== + #} ========= / CHECK FIELDS =========== + + switch ( $mode ) { + + case 'replace': + // (for actions) log starting objs + $existingTagIDs = $this->getTagsForObjID( + array( + 'objtypeid' => $objtype, + 'objid' => $objid, + 'onlyID' => true, + ) + ); + if ( ! is_array( $existingTagIDs ) ) { + $existingTagIDs = array(); + } + $removedTagsByID = array(); + $addedTagsByID = array(); + + // cull all previous + $deleted = $this->deleteTagObjLinks( + array( + 'objid' => $objid, + 'objtype' => $objtype, + ) + ); + + // cycle through & add + foreach ( $tagIDs as $tid ) { + + $added = $this->addUpdateTagObjLink( + array( + 'data' => array( + 'objid' => $objid, + 'objtype' => $objtype, + 'tagid' => $tid, + ), + ) + ); + + if ( $added !== false ) { + + if ( ! in_array( $tid, $existingTagIDs ) ) { + $addedTagsByID[] = $tid; // tag was added + } + // else + // tag was already in there, just re-added + } + } - switch ($mode){ + // actions - case 'replace': + // check removed + foreach ( $existingTagIDs as $tid ) { - // (for actions) log starting objs - $existingTagIDs = $this->getTagsForObjID(array('objtypeid'=>$objtype,'objid'=>$objid,'onlyID'=>true)); - if (!is_array($existingTagIDs)) $existingTagIDs = array(); - $removedTagsByID = array(); $addedTagsByID = array(); - - // cull all previous - $deleted = $this->deleteTagObjLinks(array('objid'=>$objid,'objtype'=>$objtype)); + if ( ! in_array( $tid, $tagIDs ) ) { + $removedTagsByID[] = $tid; + } + } - // cycle through & add - foreach ($tagIDs as $tid){ - - $added = $this->addUpdateTagObjLink(array( - 'data'=>array( - 'objid' => $objid, - 'objtype' => $objtype, - 'tagid' => $tid))); - - if ($added !== false){ - - if (!in_array($tid, $existingTagIDs)) - $addedTagsByID[] = $tid; // tag was added - //else - // tag was already in there, just re-added - } + // fire actions for each tag + // added to + if ( count( $addedTagsByID ) > 0 ) { + foreach ( $addedTagsByID as $tagID ) { + do_action( 'zbs_tag_added_to_objid', $tagID, $objtype, $objid ); } + } - // actions - - // check removed - foreach ($existingTagIDs as $tid){ - - if (!in_array($tid, $tagIDs)) $removedTagsByID[] = $tid; - - } - - // fire actions for each tag - - // added to - if (count($addedTagsByID) > 0) foreach ($addedTagsByID as $tagID) do_action('zbs_tag_added_to_objid',$tagID, $objtype, $objid); - - // removed from - if (count($removedTagsByID) > 0) foreach ($removedTagsByID as $tagID) do_action('zbs_tag_removed_from_objid',$tagID, $objtype, $objid); - - - // return - return true; - - break; - - case 'append': - - // get existing - $existingTagIDs = $this->getTagsForObjID(array('objtypeid'=>$objtype,'objid'=>$objid,'onlyID'=>true)); - - // make just ids - // no need, added ,'onlyID'=>true above - //$existingTagIDs = array(); foreach ($tags as $t) $existingTagIDs[] = $t['id']; - - // cycle through& add - foreach ($tagIDs as $tid){ - - if (!in_array($tid,$existingTagIDs)){ + // removed from + if ( count( $removedTagsByID ) > 0 ) { + foreach ( $removedTagsByID as $tagID ) { + do_action( 'zbs_tag_removed_from_objid', $tagID, $objtype, $objid ); + } + } - // add a link - $this->addUpdateTagObjLink(array( - 'data'=>array( - 'objid' => $objid, - 'objtype' => $objtype, - 'tagid' => $tid))); + // return + return true; - // fire action - do_action('zbs_tag_added_to_objid',$tid, $objtype, $objid); + break; - } + case 'append': + // get existing + $existingTagIDs = $this->getTagsForObjID( + array( + 'objtypeid' => $objtype, + 'objid' => $objid, + 'onlyID' => true, + ) + ); + + // make just ids + // no need, added ,'onlyID'=>true above + // $existingTagIDs = array(); foreach ($tags as $t) $existingTagIDs[] = $t['id']; + + // cycle through& add + foreach ( $tagIDs as $tid ) { + + if ( ! in_array( $tid, $existingTagIDs ) ) { + + // add a link + $this->addUpdateTagObjLink( + array( + 'data' => array( + 'objid' => $objid, + 'objtype' => $objtype, + 'tagid' => $tid, + ), + ) + ); + + // fire action + do_action( 'zbs_tag_added_to_objid', $tid, $objtype, $objid ); + } } $this->compile_segments_from_tagIDs( $tagIDs, $owner ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - return true; - - break; - - case 'remove': - - // get existing - $existingTagIDs = $this->getTagsForObjID(array('objtypeid'=>$objtype,'objid'=>$objid,'onlyID'=>true)); - - // cycle through & remove links - foreach ($tagIDs as $tid){ - - if (in_array($tid, $existingTagIDs)){ - - // delete link - $this->deleteTagObjLink(array( - 'objid' => $objid, - 'objtype' => $objtype, - 'tagid' => $tid)); - - // action - do_action('zbs_tag_removed_from_objid',$tid, $objtype, $objid); + return true; - } + break; + case 'remove': + // get existing + $existingTagIDs = $this->getTagsForObjID( + array( + 'objtypeid' => $objtype, + 'objid' => $objid, + 'onlyID' => true, + ) + ); + + // cycle through & remove links + foreach ( $tagIDs as $tid ) { + + if ( in_array( $tid, $existingTagIDs ) ) { + + // delete link + $this->deleteTagObjLink( + array( + 'objid' => $objid, + 'objtype' => $objtype, + 'tagid' => $tid, + ) + ); + + // action + do_action( 'zbs_tag_removed_from_objid', $tid, $objtype, $objid ); } + } - $this->compile_segments_from_tagIDs( $tagIDs, $owner ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - - return true; - - break; - + $this->compile_segments_from_tagIDs( $tagIDs, $owner ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } + return true; + break; - return false; + } - } + return false; + } /** * Compiles segments based on an array of given tag IDs @@ -4564,1093 +5207,1279 @@ public function compile_segments_from_tagIDs( $tagIDs, $owner ) { // phpcs:ignor } } - /** - * deletes a tag object link - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteTagObjLink($args=array()){ - - global $ZBSCRM_t,$wpdb; + /** + * deletes a tag object link + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteTagObjLink( $args = array() ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + global $ZBSCRM_t, $wpdb; - 'id' => -1, + #} ============ LOAD ARGS ============= + $defaultArgs = array( - // or... + 'id' => -1, - 'objtype' => -1, - 'objid' => -1, - 'tagid' => -1 + // or... + 'objtype' => -1, + 'objid' => -1, + 'tagid' => -1, - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} Check ID & Delete :) (IF ID PRESENT) - $id = (int)$id; - if ( $id > 0 ) { - return zeroBSCRM_db2_deleteGeneric($id,'taglinks'); - } + #} Check ID & Delete :) (IF ID PRESENT) + $id = (int) $id; + if ( $id > 0 ) { + return zeroBSCRM_db2_deleteGeneric( $id, 'taglinks' ); + } - #} ... else delete by objtype etc. + #} ... else delete by objtype etc. - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ // check obtype is completed + legit if ( empty( $objtype ) ) { return false; } - if ($this->objTypeKey($objtype) === -1) return false; - - // obj id - $objid = (int)$objid; if (empty($objid) || $objid < 1) return false; + if ( $this->objTypeKey( $objtype ) === -1 ) { + return false; + } - // tag id - $tagid = (int)$tagid; if (empty($tagid) || $tagid < 1) return false; + // obj id + $objid = (int) $objid; + if ( empty( $objid ) || $objid < 1 ) { + return false; + } - // CHECK PERMISSIONS? + // tag id + $tagid = (int) $tagid; + if ( empty( $tagid ) || $tagid < 1 ) { + return false; + } - #} ========= / CHECK FIELDS =========== + // CHECK PERMISSIONS? - #} ... if here then is trying to delete specific tag linkid - return $wpdb->delete( - $ZBSCRM_t['taglinks'], - array( // where - 'zbstl_objtype' => $objtype, - 'zbstl_objid' => $objid, - 'zbstl_tagid' => $tagid - ), - array( - '%d', - '%d', - '%d' - ) - ); + #} ========= / CHECK FIELDS =========== - } + #} ... if here then is trying to delete specific tag linkid + return $wpdb->delete( + $ZBSCRM_t['taglinks'], + array( // where + 'zbstl_objtype' => $objtype, + 'zbstl_objid' => $objid, + 'zbstl_tagid' => $tagid, + ), + array( + '%d', + '%d', + '%d', + ) + ); + } - /** - * deletes all tag object links for a specific obj - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteTagObjLinks($args=array()){ + /** + * deletes all tag object links for a specific obj + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteTagObjLinks( $args = array() ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'objtype' => -1, - 'objid' => -1, + 'objtype' => -1, + 'objid' => -1, - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ // check obtype is completed + legit if ( empty( $objtype ) ) { return false; } - if ($this->objTypeKey($objtype) === -1) return false; - - // obj id - $objid = (int)$objid; if (empty($objid) || $objid < 1) return false; + if ( $this->objTypeKey( $objtype ) === -1 ) { + return false; + } - // CHECK PERMISSIONS? + // obj id + $objid = (int) $objid; + if ( empty( $objid ) || $objid < 1 ) { + return false; + } - #} ========= / CHECK FIELDS =========== + // CHECK PERMISSIONS? - // brutal - return $wpdb->delete( - $ZBSCRM_t['taglinks'], - array( // where - 'zbstl_objtype' => $objtype, - 'zbstl_objid' => $objid - ), - array( - '%d', - '%d' - ) - ); + #} ========= / CHECK FIELDS =========== - } + // brutal + return $wpdb->delete( + $ZBSCRM_t['taglinks'], + array( // where + 'zbstl_objtype' => $objtype, + 'zbstl_objid' => $objid, + ), + array( + '%d', + '%d', + ) + ); + } + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_taglink( $obj = false ) { - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_taglink($obj=false){ + $res = false; - $res = false; + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ + $res['objtype'] = $obj->zbstag_objtype; + $res['name'] = $this->stripSlashes( $obj->zbstag_name ); + $res['slug'] = $obj->zbstag_slug; - $res['objtype'] = $obj->zbstag_objtype; - $res['name'] = $this->stripSlashes($obj->zbstag_name); - $res['slug'] = $obj->zbstag_slug; + $res['created'] = $obj->zbstag_created; + $res['lastupdated'] = $obj->zbstag_lastupdated; + } - $res['created'] = $obj->zbstag_created; - $res['lastupdated'] = $obj->zbstag_lastupdated; + return $res; + } - } + // =========== / TAG LINKS ================================================== + // =============================================================================== - return $res; + // =============================================================================== + // =========== CUSTOM FIELDS ================================================= + /** + * returns true if field key exists as custom field for CONTACT + * + * @param array $args Associative array of arguments + * objtypeid + * + * @return array of customfield field keys + */ + public function isActiveCustomField_Contact( $customFieldKey = '' ) { - } + #} These are simply stored in settings with a key of customfields_objtype e.g. customfields_contact + if ( ! empty( $objtypeid ) && $objtypeid > 0 && ! empty( $customFieldKey ) ) { - // =========== / TAG LINKS ================================================== - // =============================================================================== + // get custom fields + $customFields = $this->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_CONTACT ) ); + // validate there + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cfK => $cfV ) { + if ( $cfK == $customFieldKey ) { + return true; + } + } + } + } + return false; + } + /** + * returns true if field key exists as custom field for obj + * + * @param array $args Associative array of arguments + * objtypeid + * + * @return array of customfield field keys + */ + public function isActiveCustomField( $args = array() ) { + #} ============ LOAD ARGS ============= + $defaultArgs = array( + 'objtypeid' => -1, + 'customFieldKey' => '', + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + #} These are simply stored in settings with a key of customfields_objtype e.g. customfields_contact + if ( ! empty( $objtypeid ) && $objtypeid > 0 && ! empty( $customFieldKey ) ) { - // =============================================================================== - // =========== CUSTOM FIELDS ================================================= + // get custom fields + $customFields = $this->getActiveCustomFields( array( 'objtypeid' => $objtypeid ) ); - /** - * returns true if field key exists as custom field for CONTACT - * - * @param array $args Associative array of arguments - * objtypeid - * - * @return array of customfield field keys - */ - public function isActiveCustomField_Contact($customFieldKey=''){ + // validate there + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cfK => $cfV ) { - #} These are simply stored in settings with a key of customfields_objtype e.g. customfields_contact - if (!empty($objtypeid) && $objtypeid > 0 && !empty($customFieldKey)) { + if ( $cfK == $customFieldKey ) { + return true; + } + } + } + } - // get custom fields - $customFields = $this->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_CONTACT)); + return false; + } - // validate there - if (is_array($customFields)) foreach ($customFields as $cfK => $cfV){ + /** + * returns active custom field keys for an obj type + * + * @param array $args Associative array of arguments + * objtypeid + * + * @return array of customfield field keys + */ + public function getActiveCustomFields( $args = array() ) { - if ($cfK == $customFieldKey) return true; - } + #} ============ LOAD ARGS ============= + $defaultArgs = array( - } + // object type id + 'objtypeid' => -1, - return false; - } + // whether or not to accept cached variant. + // Added in gh-2019, we often recall this function on one load, this allows us to accept a once-loaded version + 'accept_cached' => true, - /** - * returns true if field key exists as custom field for obj - * - * @param array $args Associative array of arguments - * objtypeid - * - * @return array of customfield field keys - */ - public function isActiveCustomField($args=array()){ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} These are simply stored in settings with a key of customfields_objtype e.g. customfields_contact + if ( ! empty( $objtypeid ) && $objtypeid > 0 ) { - 'objtypeid' => -1, - 'customFieldKey' => '' + // retrieve + return $this->setting( 'customfields_' . $this->objTypeKey( $objtypeid ), array(), $accept_cached ); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + } - #} These are simply stored in settings with a key of customfields_objtype e.g. customfields_contact - if (!empty($objtypeid) && $objtypeid > 0 && !empty($customFieldKey)) { + return array(); + } - // get custom fields - $customFields = $this->getActiveCustomFields(array('objtypeid'=>$objtypeid)); + /** + * updates active custom field keys for an obj type + * No checking whatsoever + * + * @param array $args Associative array of arguments + * objtypeid + * + * @return array of customfield field keys + */ + public function updateActiveCustomFields( $args = array() ) { - // validate there - if (is_array($customFields)) foreach ($customFields as $cfK => $cfV){ + #} ============ LOAD ARGS ============= + $defaultArgs = array( - if ($cfK == $customFieldKey) return true; - } + 'objtypeid' => -1, + 'fields' => array(), - } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - return false; - } + #} These are simply stored in settings with a key of customfields_objtype e.g. customfields_contact + if ( ! empty( $objtypeid ) && $objtypeid > 0 ) { + return $this->updateSetting( 'customfields_' . $this->objTypeKey( $objtypeid ), $fields ); + } - /** - * returns active custom field keys for an obj type - * - * @param array $args Associative array of arguments - * objtypeid - * - * @return array of customfield field keys - */ - public function getActiveCustomFields( $args=array() ){ + return array(); + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + /** + * returns scalar value of 1 custom field line (or it's ID) + * ... real custom fields will be got as part of getCustomers more commonly (this is for 1 alone) + * + * @param array $args Associative array of arguments + * objtypeid,objid,objkey + * + * @return array result + */ + public function getCustomFieldVal( $args = array() ) { - // object type id - 'objtypeid' => -1, + #} =========== LOAD ARGS ============== + $defaultArgs = array( - // whether or not to accept cached variant. - // Added in gh-2019, we often recall this function on one load, this allows us to accept a once-loaded version - 'accept_cached' => true, + 'objtypeid' => -1, // e.g. 1 = contact + 'objid' => -1, // e.g. contact #101 + 'objkey' => '', // e.g. notes - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + // permissions + 'ignoreowner' => false, // this'll let you not-check the owner of obj - #} These are simply stored in settings with a key of customfields_objtype e.g. customfields_contact - if (!empty($objtypeid) && $objtypeid > 0) { + // returns scalar ID of line + 'onlyID' => false, - // retrieve - return $this->setting( 'customfields_'.$this->objTypeKey( $objtypeid ), array(), $accept_cached ); + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - } + #} Check IDs + $objtypeid = (int) $objtypeid; + $objid = (int) $objid; + if ( ! empty( $objtypeid ) && $objtypeid > 0 && ! empty( $objid ) && $objid > 0 && ! empty( $objkey ) ) { - return array(); - } + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - /** - * updates active custom field keys for an obj type - * No checking whatsoever - * - * @param array $args Associative array of arguments - * objtypeid - * - * @return array of customfield field keys - */ - public function updateActiveCustomFields($args=array()){ + #} Build query + $query = 'SELECT ID,zbscf_objval FROM ' . $ZBSCRM_t['customfields']; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============= WHERE ================ - 'objtypeid' => -1, - 'fields' => array() + #} Add obj type + $wheres['zbscf_objtype'] = array( 'zbscf_objtype', '=', '%d', $objtypeid ); - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} Add obj ID + $wheres['zbscf_objid'] = array( 'zbscf_objid', '=', '%d', $objid ); - #} These are simply stored in settings with a key of customfields_objtype e.g. customfields_contact - if (!empty($objtypeid) && $objtypeid > 0) { + #} Add obj key + $wheres['zbscf_objkey'] = array( 'zbscf_objkey', '=', '%s', $objkey ); - return $this->updateSetting('customfields_'.$this->objTypeKey($objtypeid),$fields); + #} ============ / WHERE ============== - } + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - return array(); - } + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - /** - * returns scalar value of 1 custom field line (or it's ID) - * ... real custom fields will be got as part of getCustomers more commonly (this is for 1 alone) - * - * @param array $args Associative array of arguments - * objtypeid,objid,objkey - * - * @return array result - */ - public function getCustomFieldVal($args=array()){ + try { - #} =========== LOAD ARGS ============== - $defaultArgs = array( + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - 'objtypeid' => -1, // e.g. 1 = contact - 'objid' => -1, // e.g. contact #101 - 'objkey' => '', // e.g. notes + } catch ( Exception $e ) { - // permissions - 'ignoreowner' => false, // this'll let you not-check the owner of obj + #} General SQL Err + $this->catchSQLError( $e ); - // returns scalar ID of line - 'onlyID' => false + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} Check IDs - $objtypeid = (int)$objtypeid; $objid = (int)$objid; - if (!empty($objtypeid) && $objtypeid > 0 && !empty($objid) && $objid > 0 && !empty($objkey)){ + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + #} Has results, tidy + return - #} Build query - $query = "SELECT ID,zbscf_objval FROM ".$ZBSCRM_t['customfields']; + #} Only ID? return it directly + if ( $onlyID === true ) { + return $potentialRes->ID; + } - #} ============= WHERE ================ + // tidy + $res = $this->tidy_customfieldvalSingular( $potentialRes ); - #} Add obj type - $wheres['zbscf_objtype'] = array('zbscf_objtype','=','%d',$objtypeid); + return $res; - #} Add obj ID - $wheres['zbscf_objid'] = array('zbscf_objid','=','%d',$objid); + } + } // / if ID - #} Add obj key - $wheres['zbscf_objkey'] = array('zbscf_objkey','=','%s',$objkey); + return false; + } - #} ============ / WHERE ============== + /** + * adds or updates a customfield object + * NOTE: because these are specific to unique ID of obj, there's no need for site/team etc. here + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateCustomField( $args = array() ) { - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + global $ZBSCRM_t, $wpdb; - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} ============ LOAD ARGS ============= + $defaultArgs = array( - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + 'id' => -1, // Custom field line ID (not obj id!) + 'owner' => -1, - try { + // fields (directly) + 'data' => array( + 'objtype' => -1, + 'objid' => -1, + 'objkey' => '', + 'objval' => 'NULL', + ), - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - } catch (Exception $e){ + #} ========== CHECK FIELDS ============ - #} General SQL Err - $this->catchSQLError($e); + $id = (int) $id; - } + if ( ! empty( $data['objid'] ) ) { // phpcs:ignore -- PHPCS chokes on this line, but the var does exist. + $data['objid'] = (int) $data['objid']; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + } + if ( isset( $data['objtype'] ) ) { + $data['objtype'] = (int) $data['objtype']; + } - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + // check obtype is completed + legit + if ( ! isset( $data['objtype'] ) || empty( $data['objtype'] ) ) { + return false; + } + if ( $this->objTypeKey( $data['objtype'] ) === -1 ) { + return false; + } - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID === true) return $potentialRes->ID; + // check key + ID present + if ( ! isset( $data['objkey'] ) || empty( $data['objkey'] ) ) { + return false; + } + if ( $data['objid'] <= 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + return false; + } - // tidy - $res = $this->tidy_customfieldvalSingular($potentialRes); + // if owner = -1, add current + if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $owner = zeroBSCRM_user(); + } - return $res; + // ID finder - if obj id + key + val + typeid provided, check CF not already present (if so overwrite) + if ( ( empty( $id ) || $id <= 0 ) + && + ( isset( $data['objtype'] ) && ! empty( $data['objtype'] ) ) + && + ( isset( $data['objid'] ) && ! empty( $data['objid'] ) ) + && + ( isset( $data['objkey'] ) && ! empty( $data['objkey'] ) ) ) { + + // check existence + return ID + $potentialID = (int) $this->getCustomFieldVal( + array( + 'objtypeid' => $data['objtype'], + 'objid' => $data['objid'], + 'objkey' => $data['objkey'], + 'onlyID' => true, + 'ignoreowner' => true, + ) + ); + // override empty ID + if ( ! empty( $potentialID ) && $potentialID > 0 ) { + $id = $potentialID; + } + } - } + // handle radio, select, and checkbox fields + if ( is_array( $data['objval'] ) ) { + $data['objval'] = implode( ',', $data['objval'] ); + } - } // / if ID + #} ========= / CHECK FIELDS =========== - return false; + #} Check if ID present + if ( ! empty( $id ) && $id > 0 ) { - } + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - /** - * adds or updates a customfield object - * NOTE: because these are specific to unique ID of obj, there's no need for site/team etc. here - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateCustomField($args=array()){ + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['customfields'], + array( - global $ZBSCRM_t,$wpdb; + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $owner, + + // fields + 'zbscf_objtype' => $data['objtype'], + 'zbscf_objid' => $data['objid'], + 'zbscf_objkey' => $data['objkey'], + 'zbscf_objval' => $data['objval'], + + // 'zbscf_created' => time(), + 'zbscf_lastupdated' => time(), + ), + array( // where + 'ID' => $id, + ), + array( // field data types + // '%d', // site + // '%d', // team + '%d', // owner + + '%d', + '%d', + '%s', + '%s', + + '%d', // last updated + ), + array( // where data types + '%d', + ) + ) !== false ) { - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // Successfully updated - Return id + return $id; - 'id' => -1, // Custom field line ID (not obj id!) - 'owner' => -1, + } else { - // fields (directly) - 'data' => array( - 'objtype' => -1, - 'objid' => -1, - 'objkey' => '', - 'objval' => 'NULL' - ) + // FAILED update + return false; - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + } + } else { + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['customfields'], + array( - #} ========== CHECK FIELDS ============ + // ownership + 'zbs_site' => zeroBSCRM_site(), + 'zbs_team' => zeroBSCRM_team(), + 'zbs_owner' => $owner, + + // fields + 'zbscf_objtype' => $data['objtype'], + 'zbscf_objid' => $data['objid'], + 'zbscf_objkey' => $data['objkey'], + 'zbscf_objval' => $data['objval'], + + 'zbscf_created' => time(), + 'zbscf_lastupdated' => time(), + ), + array( // field data types + '%d', // site + '%d', // team + '%d', // owner + + '%d', + '%d', + '%s', + '%s', + + '%d', + '%d', + ) + ) > 0 ) { + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + return $newID; - $id = (int)$id; + } else { - if ( ! empty( $data['objid'] ) ) { // phpcs:ignore -- PHPCS chokes on this line, but the var does exist. - $data['objid'] = (int) $data['objid']; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + #} Failed to Insert + return false; + + } } - if (isset($data['objtype'])) $data['objtype'] = (int)$data['objtype']; - // check obtype is completed + legit - if (!isset($data['objtype']) || empty($data['objtype'])) return false; - if ($this->objTypeKey($data['objtype']) === -1) return false; + return false; + } - // check key + ID present - if (!isset($data['objkey']) || empty($data['objkey'])) return false; - if ( $data['objid'] <= 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - return false; + /** + * deletes a customfield object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteCustomField( $args = array() ) { + + global $ZBSCRM_t, $wpdb; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } } + #} =========== / LOAD ARGS ============ + + #} Check ID & Delete :) + $id = (int) $id; + return zeroBSCRM_db2_deleteGeneric( $id, 'customfields' ); + } + + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_customfieldvalSingular( $obj = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + + // just return the value here! + $res = $this->stripSlashes( $obj->zbscf_objval ); - // if owner = -1, add current - if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $owner = zeroBSCRM_user(); } - // ID finder - if obj id + key + val + typeid provided, check CF not already present (if so overwrite) - if ((empty($id) || $id <= 0) - && - (isset($data['objtype']) && !empty($data['objtype'])) - && - (isset($data['objid']) && !empty($data['objid'])) - && - (isset($data['objkey']) && !empty($data['objkey']))) { - - // check existence + return ID - $potentialID = (int)$this->getCustomFieldVal(array( - 'objtypeid' => $data['objtype'], - 'objid' => $data['objid'], - 'objkey' => $data['objkey'], - 'onlyID' => true, - 'ignoreowner' => true - )); - // override empty ID - if (!empty($potentialID) && $potentialID > 0) $id = $potentialID; - - } - - // handle radio, select, and checkbox fields - if( is_array( $data['objval'] ) ) { - $data['objval'] = implode( ',', $data['objval'] ); - } - - #} ========= / CHECK FIELDS =========== - - #} Check if ID present - if (!empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['customfields'], - array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $owner, - - // fields - 'zbscf_objtype' => $data['objtype'], - 'zbscf_objid' => $data['objid'], - 'zbscf_objkey' => $data['objkey'], - 'zbscf_objval' => $data['objval'], - - //'zbscf_created' => time(), - 'zbscf_lastupdated' => time() - ), - array( // where - 'ID' => $id - ), - array( // field data types - //'%d', // site - //'%d', // team - '%d', // owner - - '%d', - '%d', - '%s', - '%s', - - '%d' // last updated - ), - array( // where data types - '%d' - )) !== false){ - - // Successfully updated - Return id - return $id; - - } else { - - // FAILED update - return false; - - } - - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['customfields'], - array( + return $res; + } - // ownership - 'zbs_site' => zeroBSCRM_site(), - 'zbs_team' => zeroBSCRM_team(), - 'zbs_owner' => $owner, + // =========== / CUSTOM FIELDS =============================================== + // =============================================================================== - // fields - 'zbscf_objtype' => $data['objtype'], - 'zbscf_objid' => $data['objid'], - 'zbscf_objkey' => $data['objkey'], - 'zbscf_objval' => $data['objval'], - - 'zbscf_created' => time(), - 'zbscf_lastupdated' => time() - ), - array( // field data types - '%d', // site - '%d', // team - '%d', // owner - - '%d', - '%d', - '%s', - '%s', - - '%d', - '%d' - ) ) > 0){ + // =============================================================================== + // =========== EXTERNAL SOURCES =============================================== + /** + * returns first external source line +- details + * + * @param int id tag id + * @param array $args Associative array of arguments + * withStats + * + * @return array result + */ + public function getExternalSource( $id = -1, $args = array() ) { - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - return $newID; + #} =========== LOAD ARGS ============== + $defaultArgs = array( - } else { + // Alternative search criteria to ID :) + // .. LEAVE blank if using ID + // 'contactID' => -1, // NOTE: This only returns the FIRST source, if using multiple sources, use getExternalSourcesForContact + 'objectID' => -1, + 'objectType' => -1, + 'source' => -1, // Optional, if used with contact ID will return 1 line :D + 'origin' => '', // Optional + + // permissions + 'ignoreowner' => true, // this'll let you not-check the owner of obj + + // returns scalar ID of line + 'onlyID' => false, + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + + #} ========== CHECK FIELDS ============ + + $id = (int) $id; + $objectID = (int) $objectID; + $objectType = (int) $objectType; + + #} ========= / CHECK FIELDS =========== + + #} Check ID or name/type + if ( + $objectType > 0 && + ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $objectID ) && $objectID > 0 ) + ) + ) { - #} Failed to Insert - return false; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - } + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['externalsources']; - } - - return false; - - } - - /** - * deletes a customfield object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteCustomField($args=array()){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1 - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} Check ID & Delete :) - $id = (int)$id; - return zeroBSCRM_db2_deleteGeneric( $id, 'customfields' ); + #} ============= WHERE ================ - } + // Line ID + if ( ! empty( $id ) && $id > 0 ) { + $wheres['ID'] = array( 'ID', '=', '%d', $id ); + } - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_customfieldvalSingular($obj=false){ + // Object ID + if ( ! empty( $objectID ) && $objectID > 0 ) { + $wheres['zbss_objid'] = array( 'zbss_objid', '=', '%d', $objectID ); + } - $res = false; + $wheres['zbss_objtype'] = array( 'zbss_objtype', '=', '%d', $objectType ); - if (isset($obj->ID)){ + // Source + if ( ! empty( $source ) && $source !== -1 ) { + $wheres['zbss_source'] = array( 'zbss_source', '=', '%s', $source ); + } - // just return the value here! - $res = $this->stripSlashes($obj->zbscf_objval); + // Origin + if ( ! empty( $origin ) ) { + $wheres['zbss_origin'] = array( 'zbss_origin', '=', '%s', $origin ); + } - } + #} ============ / WHERE ============== - return $res; + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - } + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); + try { - // =========== / CUSTOM FIELDS =============================================== - // =============================================================================== + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); + } catch ( Exception $e ) { - // =============================================================================== - // =========== EXTERNAL SOURCES =============================================== - /** - * returns first external source line +- details - * - * @param int id tag id - * @param array $args Associative array of arguments - * withStats - * - * @return array result - */ - public function getExternalSource( $id=-1, $args=array() ){ + #} General SQL Err + $this->catchSQLError( $e ); - #} =========== LOAD ARGS ============== - $defaultArgs = array( + } - // Alternative search criteria to ID :) - // .. LEAVE blank if using ID - //'contactID' => -1, // NOTE: This only returns the FIRST source, if using multiple sources, use getExternalSourcesForContact - 'objectID' => -1, - 'objectType' => -1, - 'source' => -1, // Optional, if used with contact ID will return 1 line :D - 'origin' => '', // Optional + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj + #} Has results, tidy + return - // returns scalar ID of line - 'onlyID' => false + #} Only ID? return it directly + if ( $onlyID === true ) { + return $potentialRes->ID; + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} ========== CHECK FIELDS ============ + // tidy + $res = $this->tidy_externalsource( $potentialRes ); - $id = (int)$id; - $objectID = (int)$objectID; - $objectType = (int)$objectType; + return $res; - #} ========= / CHECK FIELDS =========== - - #} Check ID or name/type - if ( - $objectType > 0 && - ( - (!empty($id) && $id > 0) - || - (!empty($objectID) && $objectID > 0) - ) - ){ + } + } // / if ID - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + return false; + } - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['externalsources']; + /** + * returns multiple external source line +- details + * + * @param int id tag id + * @param array $args Associative array of arguments + * withStats + * + * @return array results + */ + public function getExternalSources( $id = -1, $args = array() ) { - #} ============= WHERE ================ + #} =========== LOAD ARGS ============== + $defaultArgs = array( - // Line ID - if (!empty($id) && $id > 0) { - $wheres['ID'] = array('ID','=','%d',$id); - } + 'objectID' => -1, + 'objectType' => -1, - // Object ID - if (!empty($objectID) && $objectID > 0) { - $wheres['zbss_objid'] = array( 'zbss_objid', '=', '%d', $objectID ); - } + 'grouped_by_source' => false, // if true, will return array organised by source (e.g. array('woo'=>array({woosources}))) - $wheres['zbss_objtype'] = array( 'zbss_objtype', '=', '%d', $objectType ); + // permissions + 'ignoreowner' => true, // this'll let you not-check the owner of obj - // Source - if (!empty($source) && $source !== -1) { - $wheres['zbss_source'] = array( 'zbss_source', '=', '%s', $source ); - } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // Origin - if ( !empty( $origin ) ) { - $wheres['zbss_origin'] = array( 'zbss_origin', '=', '%s', $origin ); - } + #} ========== CHECK FIELDS ============ - #} ============ / WHERE ============== + $id = (int) $id; + $objectID = (int) $objectID; + $objectType = (int) $objectType; - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} ========= / CHECK FIELDS =========== - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Check ID or name/type + if ( + $objectType > 0 && + ( + ( ! empty( $id ) && $id > 0 ) + || + ( ! empty( $objectID ) && $objectID > 0 ) + ) + ) { - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - try { + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['externalsources']; - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); - - } catch (Exception $e){ + #} ============= WHERE ================ - #} General SQL Err - $this->catchSQLError($e); + #} Add ID + if ( ! empty( $id ) && $id > 0 ) { + $wheres['ID'] = array( 'ID', '=', '%d', $id ); + } - } + #} zbss_objid + if ( ! empty( $objectID ) && $objectID > 0 ) { + $wheres['zbss_objid'] = array( 'zbss_objid', '=', '%d', $objectID ); + } - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + // zbss_objid + $wheres['zbss_objtype'] = array( 'zbss_objtype', '=', '%d', $objectType ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID === true) return $potentialRes->ID; - - // tidy - $res = $this->tidy_externalsource($potentialRes); + #} ============ / WHERE ============== - return $res; + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - } + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - } // / if ID + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1000 ); - return false; + try { - } + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); + } catch ( Exception $e ) { + #} General SQL Err + $this->catchSQLError( $e ); - /** - * returns multiple external source line +- details - * - * @param int id tag id - * @param array $args Associative array of arguments - * withStats - * - * @return array results - */ - public function getExternalSources($id=-1,$args=array()){ + } - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - 'objectID' => -1, - 'objectType' => -1, + $res = array(); - 'grouped_by_source' => false, // if true, will return array organised by source (e.g. array('woo'=>array({woosources}))) + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj + #} Has results, tidy + return + foreach ( $potentialRes as $data_line ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} ========== CHECK FIELDS ============ + // default simple array + if ( ! $grouped_by_source ) { - $id = (int)$id; - $objectID = (int)$objectID; - $objectType = (int)$objectType; + // tidy + $res[] = $this->tidy_externalsource( $data_line ); - #} ========= / CHECK FIELDS =========== - - #} Check ID or name/type - if ( - $objectType > 0 && - ( - (!empty($id) && $id > 0) - || - (!empty($objectID) && $objectID > 0) - ) - ){ + } else { - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + $tidied_line = $this->tidy_externalsource( $data_line ); - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['externalsources']; + // grouped by source adds another dimension to array, keyed by source (e.g. 'woo') + if ( ! isset( $res[ $tidied_line['source'] ] ) ) { - #} ============= WHERE ================ + $res[ $tidied_line['source'] ] = array(); - #} Add ID - if (!empty($id) && $id > 0) $wheres['ID'] = array('ID','=','%d',$id); + } - #} zbss_objid - if (!empty($objectID) && $objectID > 0) $wheres['zbss_objid'] = array('zbss_objid','=','%d',$objectID); + $res[ $tidied_line['source'] ][] = $tidied_line; - // zbss_objid - $wheres['zbss_objtype'] = array( 'zbss_objtype', '=', '%d', $objectType ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } + } + } - #} ============ / WHERE ============== + return $res; - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + } // / if ID - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + return false; + } - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1000); + /** + * adds or updates an external source object + * + * @param array $args Associative array of arguments + * + * @return int line ID + */ + public function addUpdateExternalSource( $args = array() ) { - try { + global $ZBSCRM_t, $wpdb; - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} ============ LOAD ARGS ============= + $defaultArgs = array( - } catch (Exception $e){ + 'id' => -1, - #} General SQL Err - $this->catchSQLError($e); + // fields (directly) + 'data' => array( - } + 'objectType' => -1, + 'objectID' => -1, + 'source' => '', + 'uid' => '', + 'origin' => '', + 'owner' => 0, // -1 for current user, for now, disregard owenship for ext sources - $res = array(); + ), - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} Has results, tidy + return - foreach ( $potentialRes as $data_line ){ + #} ========== CHECK FIELDS ============ - // default simple array - if ( !$grouped_by_source ){ - - // tidy - $res[] = $this->tidy_externalsource( $data_line ); + $id = (int) $id; - } else { + // objectType + if ( empty( $data['objectType'] ) || $data['objectType'] <= 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + return false; + } - $tidied_line = $this->tidy_externalsource( $data_line ); + // objectID + if ( ! isset( $data['objectID'] ) || $data['objectID'] <= 0 ) { + return false; + } - // grouped by source adds another dimension to array, keyed by source (e.g. 'woo') - if ( !isset( $res[ $tidied_line['source'] ] ) ){ - - $res[ $tidied_line['source'] ] = array(); + // if owner = -1, add current + if ( ! isset( $data['owner'] ) || $data['owner'] === -1 ) { + $data['owner'] = zeroBSCRM_user(); + } - } + // check name present + legit + if ( ! isset( $data['source'] ) || empty( $data['source'] ) ) { + return false; + } - $res[ $tidied_line['source'] ][] = $tidied_line; + // extsource ID finder - if obj source + cid provided, check not already present (if so overwrite) + // keeps unique... + if ( ( empty( $id ) || $id <= 0 ) + && + ( + ( isset( $data['objectType'] ) && ! empty( $data['objectType'] ) ) || + ( isset( $data['objectID'] ) && ! empty( $data['objectID'] ) ) || + ( isset( $data['source'] ) && ! empty( $data['source'] ) ) + ) ) { + + $args = array( + 'objectType' => $data['objectType'], + 'objectID' => $data['objectID'], + 'source' => $data['source'], + 'onlyID' => true, + ); - } + // check by source + cid + // check existence + return ID + $potentialID = (int) $this->getExternalSource( -1, $args ); - } - } + // override empty ID + if ( ! empty( $potentialID ) && $potentialID > 0 ) { + $id = $potentialID; + } + } - return $res; + #} ========= / CHECK FIELDS =========== - } // / if ID + #} Check if ID present + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - return false; + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - } + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['externalsources'], + array( - /** - * adds or updates an external source object - * - * @param array $args Associative array of arguments - * - * @return int line ID - */ - public function addUpdateExternalSource($args=array()){ + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $data['owner'], + + // fields + 'zbss_objid' => $data['objectID'], + 'zbss_objtype' => $data['objectType'], + 'zbss_source' => $data['source'], + 'zbss_uid' => $data['uid'], + 'zbss_origin' => $data['origin'], + 'zbss_lastupdated' => time(), + + ), + array( // where + 'ID' => $id, + ), + array( // field data types + '%d', + '%d', + '%d', + '%s', + '%s', + '%s', + '%d', + ), + array( // where data types + '%d', + ) + ) !== false ) { - global $ZBSCRM_t,$wpdb; + // Successfully updated - Return id + return $id; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } else { - 'id' => -1, + // FAILED update + return false; - // fields (directly) - 'data' => array( + } + } else { - 'objectType' => -1, - 'objectID' => -1, - 'source' => '', - 'uid' => '', - 'origin' => '', - 'owner' => 0 // -1 for current user, for now, disregard owenship for ext sources + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['externalsources'], + array( - ) + // ownership + 'zbs_site' => zeroBSCRM_site(), + 'zbs_team' => zeroBSCRM_team(), + 'zbs_owner' => $data['owner'], + + // fields + 'zbss_objid' => $data['objectID'], + 'zbss_objtype' => $data['objectType'], + 'zbss_source' => $data['source'], + 'zbss_uid' => $data['uid'], + 'zbss_origin' => $data['origin'], + 'zbss_created' => time(), + 'zbss_lastupdated' => time(), + ), + array( // field data types + '%d', // site + '%d', // team + '%d', // owner + + '%d', + '%d', + '%s', + '%s', + '%s', + '%d', + '%d', + ) + ) > 0 ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - #} ========== CHECK FIELDS ============ + return $newID; + } else { - $id = (int)$id; + #} Failed to Insert + return false; - // objectType - if ( empty( $data['objectType'] ) || $data['objectType'] <= 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - return false; + } } - // objectID - if (!isset($data['objectID']) || $data['objectID'] <= 0) return false; - - // if owner = -1, add current - if (!isset($data['owner']) || $data['owner'] === -1) $data['owner'] = zeroBSCRM_user(); - - // check name present + legit - if (!isset($data['source']) || empty($data['source'])) return false; - - // extsource ID finder - if obj source + cid provided, check not already present (if so overwrite) - // keeps unique... - if ((empty($id) || $id <= 0) - && - ( - (isset($data['objectType']) && !empty($data['objectType'])) || - (isset($data['objectID']) && !empty($data['objectID'])) || - (isset($data['source']) && !empty($data['source'])) - )) { - - $args = array( - 'objectType' => $data['objectType'], - 'objectID' => $data['objectID'], - 'source' => $data['source'], - 'onlyID' => true - ); - - // check by source + cid - // check existence + return ID - $potentialID = (int)$this->getExternalSource( -1, $args ); - - // override empty ID - if (!empty($potentialID) && $potentialID > 0) $id = $potentialID; - - } - - - #} ========= / CHECK FIELDS =========== - - #} Check if ID present - $id = (int)$id; - if (!empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['externalsources'], - array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $data['owner'], - - // fields - 'zbss_objid' => $data['objectID'], - 'zbss_objtype' => $data['objectType'], - 'zbss_source' => $data['source'], - 'zbss_uid' => $data['uid'], - 'zbss_origin' => $data['origin'], - 'zbss_lastupdated' => time() - - ), - array( // where - 'ID' => $id - ), - array( // field data types - '%d', - '%d', - '%d', - '%s', - '%s', - '%s', - '%d' - ), - array( // where data types - '%d' - )) !== false){ - - // Successfully updated - Return id - return $id; - - } else { - - // FAILED update - return false; - - } - - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['externalsources'], - array( - - // ownership - 'zbs_site' => zeroBSCRM_site(), - 'zbs_team' => zeroBSCRM_team(), - 'zbs_owner' => $data['owner'], - - // fields - 'zbss_objid' => $data['objectID'], - 'zbss_objtype' => $data['objectType'], - 'zbss_source' => $data['source'], - 'zbss_uid' => $data['uid'], - 'zbss_origin' => $data['origin'], - 'zbss_created' => time(), - 'zbss_lastupdated' => time() - ), - array( // field data types - '%d', // site - '%d', // team - '%d', // owner - - '%d', - '%d', - '%s', - '%s', - '%s', - '%d', - '%d' - ) ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - - return $newID; - - } else { - - #} Failed to Insert - return false; - - } - - } - - return false; - - } - + return false; + } /** * adds or updates an object's external sources @@ -5668,12 +6497,26 @@ public function addUpdateExternalSources( $args = array() ) { 'obj_type_id' => -1, 'external_sources' => array(), - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } // =========== / LOAD ARGS ============ - $obj_id = (int)$obj_id; - $obj_type_id = (int)$obj_type_id; - if ( !is_array( $external_sources ) ) { + $obj_id = (int) $obj_id; + $obj_type_id = (int) $obj_type_id; + if ( ! is_array( $external_sources ) ) { return ''; } @@ -5682,7 +6525,7 @@ public function addUpdateExternalSources( $args = array() ) { foreach ( $external_sources as $es ) { $external_source_id = isset( $es['id'] ) ? $es['id'] : -1; - $origin = isset( $es['origin'] ) ? $es['origin'] : null; + $origin = isset( $es['origin'] ) ? $es['origin'] : null; $external_source_id = $this->addUpdateExternalSource( array( @@ -5713,210 +6556,225 @@ public function addUpdateExternalSources( $args = array() ) { // this is a bit hackish, but allows DRY code without a refactor return $approvedExternalSource; - } - /** - * deletes an external source object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteExternalSource($args=array()){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1 - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} Check ID & Delete :) - $id = (int)$id; - return zeroBSCRM_db2_deleteGeneric( $id, 'externalsources' ); - - } - - /** - * deletes all external source lines for a specific obj - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function delete_external_sources( $args = array() ){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'obj_type' => -1, - 'obj_id' => -1, - 'obj_source' => 'all', // 'all' = every source - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} ========== CHECK FIELDS ============ + /** + * deletes an external source object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteExternalSource( $args = array() ) { - // checks - if ( empty( $obj_type ) || $this->objTypeKey( $obj_type ) === -1) { - return false; - } - if ( empty( $obj_id ) ){ - return false; - } + global $ZBSCRM_t, $wpdb; - #} ========= / CHECK FIELDS =========== + #} ============ LOAD ARGS ============= + $defaultArgs = array( - // basics - $where = array( // where - 'zbss_objtype' => $obj_type, - 'zbss_objid' => $obj_id - ); + 'id' => -1, - $whereFormat = array( // where - '%d', - '%d' - ); + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - // add source if passed add where clause for it (can delete just for a particular source) - if ( $obj_source !== 'all' ){ - $where['zbss_source'] = $obj_source; - $whereFormat[] = '%s'; - } + #} Check ID & Delete :) + $id = (int) $id; + return zeroBSCRM_db2_deleteGeneric( $id, 'externalsources' ); + } - // brutal - return $wpdb->delete( - $ZBSCRM_t['externalsources'], - $where, - $whereFormat); + /** + * deletes all external source lines for a specific obj + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function delete_external_sources( $args = array() ) { - } + global $ZBSCRM_t, $wpdb; - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - public function tidy_externalsource($obj=false){ + #} ============ LOAD ARGS ============= + $defaultArgs = array( - $res = false; + 'obj_type' => -1, + 'obj_id' => -1, + 'obj_source' => 'all', // 'all' = every source - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - $res['objid'] = $obj->zbss_objid; - $res['objtype'] = $obj->zbss_objtype; - $res['source'] = $obj->zbss_source; - $res['uid'] = $this->stripSlashes( $obj->zbss_uid ); - $res['origin'] = $this->stripSlashes( $obj->zbss_origin ); + #} ========== CHECK FIELDS ============ + // checks + if ( empty( $obj_type ) || $this->objTypeKey( $obj_type ) === -1 ) { + return false; + } + if ( empty( $obj_id ) ) { + return false; + } - $res['created'] = $obj->zbss_created; - $res['lastupdated'] = $obj->zbss_lastupdated; + #} ========= / CHECK FIELDS =========== - } + // basics + $where = array( // where + 'zbss_objtype' => $obj_type, + 'zbss_objid' => $obj_id, + ); - return $res; + $whereFormat = array( // where + '%d', + '%d', + ); + // add source if passed add where clause for it (can delete just for a particular source) + if ( $obj_source !== 'all' ) { + $where['zbss_source'] = $obj_source; + $whereFormat[] = '%s'; + } - } + // brutal + return $wpdb->delete( + $ZBSCRM_t['externalsources'], + $where, + $whereFormat + ); + } + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + public function tidy_externalsource( $obj = false ) { + $res = false; - /** - * Returns a clean domain origin string for use with external sources, where possible - * - * @return string|bool(false) - tidied up domain origin, or false - */ - public function clean_external_source_domain_string( $domain ){ + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ - // clean it up a bit - $origin = str_replace( array( 'https://', 'http://' ), '', $domain ); - $origin = rtrim( $origin, "/" ); + $res['objid'] = $obj->zbss_objid; + $res['objtype'] = $obj->zbss_objtype; + $res['source'] = $obj->zbss_source; + $res['uid'] = $this->stripSlashes( $obj->zbss_uid ); + $res['origin'] = $this->stripSlashes( $obj->zbss_origin ); - // prefix it for later querying - if ( !empty( $origin ) ){ - - return $origin; + $res['created'] = $obj->zbss_created; + $res['lastupdated'] = $obj->zbss_lastupdated; - } + } - return false; + return $res; + } - } + /** + * Returns a clean domain origin string for use with external sources, where possible + * + * @return string|bool(false) - tidied up domain origin, or false + */ + public function clean_external_source_domain_string( $domain ) { + // clean it up a bit + $origin = str_replace( array( 'https://', 'http://' ), '', $domain ); + $origin = rtrim( $origin, '/' ); - // =========== / External Sources =========================================== - // =============================================================================== + // prefix it for later querying + if ( ! empty( $origin ) ) { + return $origin; - // =============================================================================== - // =========== Origin Helpers ============================================== - // To start with these will help store origin strings for external sources in a - // machine-readable format + } - /** - * Returns a prefixed origin string - * (Currently only origins stored are domains) - * - * @param string $string - string to prefix - * @param string $origin_type - a type of origin record - * - * @return string|bool(false) - prefixed origin string, or false - */ - public function add_origin_prefix( $string, $origin_type ){ + return false; + } - switch ( $origin_type ){ + // =========== / External Sources =========================================== + // =============================================================================== - case 'domain': - return $this->prefix_domain . $string; - break; + // =============================================================================== + // =========== Origin Helpers ============================================== + // To start with these will help store origin strings for external sources in a + // machine-readable format + /** + * Returns a prefixed origin string + * (Currently only origins stored are domains) + * + * @param string $string - string to prefix + * @param string $origin_type - a type of origin record + * + * @return string|bool(false) - prefixed origin string, or false + */ + public function add_origin_prefix( $string, $origin_type ) { - } + switch ( $origin_type ) { - return false; + case 'domain': + return $this->prefix_domain . $string; + break; - } + } - /** - * Returns a de-prefixed origin string - * - * @param string $string - string to prefix - * - * @return string|bool(false) - deprefixed origin string, or false - */ - public function remove_origin_prefix( $string ){ + return false; + } - // split at first : - $split_point = strpos( $string, ':' ); + /** + * Returns a de-prefixed origin string + * + * @param string $string - string to prefix + * + * @return string|bool(false) - deprefixed origin string, or false + */ + public function remove_origin_prefix( $string ) { - if ( $split_point ){ + // split at first : + $split_point = strpos( $string, ':' ); - return substr( $string, $split_point+1 ); + if ( $split_point ) { - } + return substr( $string, $split_point + 1 ); - return false; + } - } + return false; + } /** * Returns an origin string and type from a prefixed origin string @@ -5940,372 +6798,411 @@ public function hydrate_origin( $string ) { return false; } - // =========== / Origin Helpers ============================================= - // =============================================================================== + // =========== / Origin Helpers ============================================= + // =============================================================================== + // =============================================================================== + // =========== Web Tracking (UTM etc.) ======================================== + /** + * returns full tracking line +- details + * + * @param int id tag id + * @param array $args Associative array of arguments + * withStats + * + * @return array result + */ + public function getTracking( $id = -1, $args = array() ) { - // =============================================================================== - // =========== Web Tracking (UTM etc.) ======================================== + #} =========== LOAD ARGS ============== + $defaultArgs = array( - /** - * returns full tracking line +- details - * - * @param int id tag id - * @param array $args Associative array of arguments - * withStats - * - * @return array result - */ - public function getTracking($id=-1,$args=array()){ + // permissions + 'ignoreowner' => false, // this'll let you not-check the owner of obj - #} =========== LOAD ARGS ============== - $defaultArgs = array( + // returns scalar ID of line + 'onlyID' => false, - // permissions - 'ignoreowner' => false, // this'll let you not-check the owner of obj + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // returns scalar ID of line - 'onlyID' => false + #} ========== CHECK FIELDS ============ - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} ========== CHECK FIELDS ============ + $id = (int) $id; + #} ========= / CHECK FIELDS =========== - $id = (int)$id; - #} ========= / CHECK FIELDS =========== - - #} Check ID or name/type - if (!empty($id) && $id > 0){ + #} Check ID or name/type + if ( ! empty( $id ) && $id > 0 ) { - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['tracking']; + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['tracking']; - #} ============= WHERE ================ + #} ============= WHERE ================ // Add ID $wheres['ID'] = array( 'ID', '=', '%d', $id ); - #} ============ / WHERE ============== + #} ============ / WHERE ============== - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - try { + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + try { - } catch (Exception $e){ + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - #} General SQL Err - $this->catchSQLError($e); + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + } - #} Has results, tidy + return - - #} Only ID? return it directly - if ($onlyID === true) return $potentialRes->ID; - - // tidy - $res = $this->tidy_tracking($potentialRes); + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - return $res; + #} Has results, tidy + return - } + #} Only ID? return it directly + if ( $onlyID === true ) { + return $potentialRes->ID; + } - } // / if ID + // tidy + $res = $this->tidy_tracking( $potentialRes ); - return false; + return $res; - } + } + } // / if ID + return false; + } - /** - * adds or updates a tracking object - * - * @param array $args Associative array of arguments - * - * @return int line ID - */ - public function addUpdateTracking($args=array()){ + /** + * adds or updates a tracking object + * + * @param array $args Associative array of arguments + * + * @return int line ID + */ + public function addUpdateTracking( $args = array() ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'id' => -1, + 'id' => -1, - // fields (directly) - 'data' => array( + // fields (directly) + 'data' => array( - 'contactID' => -1, - 'action' => '', - 'action_detail' => '', - 'referrer' => '', - 'utm_source' => '', - 'utm_medium' => '', - 'utm_name' => '', - 'utm_term' => '', - 'utm_content' => '', + 'contactID' => -1, + 'action' => '', + 'action_detail' => '', + 'referrer' => '', + 'utm_source' => '', + 'utm_medium' => '', + 'utm_name' => '', + 'utm_term' => '', + 'utm_content' => '', - 'owner' => -1 + 'owner' => -1, - ) + ), - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ - $id = (int)$id; + $id = (int) $id; // contactID if ( empty( $data['contactID'] ) || $data['contactID'] <= 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable return false; } - // if owner = -1, add current - if (!isset($data['owner']) || $data['owner'] === -1) $data['owner'] = zeroBSCRM_user(); - - // check action present + legit - if (!isset($data['action']) || empty($data['action'])) return false; - - #} ========= / CHECK FIELDS =========== - - #} Check if ID present - $id = (int)$id; - if (!empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['tracking'], - array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $data['owner'], - - // fields - 'zbst_contactid' => $data['contactID'], - 'zbst_action' => $data['action'], - 'zbst_action_detail' => $data['action_detail'], - 'zbst_referrer' => $data['referrer'], - 'zbst_utm_source' => $data['utm_source'], - 'zbst_utm_medium' => $data['utm_medium'], - 'zbst_utm_name' => $data['utm_name'], - 'zbst_utm_term' => $data['utm_term'], - 'zbst_utm_content' => $data['utm_content'], - - 'zbst_lastupdated' => time() - ), - array( // where - 'ID' => $id - ), - array( // field data types - '%d', - - '%d', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - - '%d' - ), - array( // where data types - '%d' - )) !== false){ - - // Successfully updated - Return id - return $id; - - } else { - - // FAILED update - return false; - - } - - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['tracking'], - array( - - // ownership - 'zbs_site' => zeroBSCRM_site(), - 'zbs_team' => zeroBSCRM_team(), - 'zbs_owner' => $data['owner'], - - // fields - 'zbst_contactid' => $data['contactID'], - 'zbst_action' => $data['action'], - 'zbst_action_detail' => $data['action_detail'], - 'zbst_referrer' => $data['referrer'], - 'zbst_utm_source' => $data['utm_source'], - 'zbst_utm_medium' => $data['utm_medium'], - 'zbst_utm_name' => $data['utm_name'], - 'zbst_utm_term' => $data['utm_term'], - 'zbst_utm_content' => $data['utm_content'], - - 'zbst_created' => time(), - 'zbst_lastupdated' => time() - ), - array( // field data types - '%d', // site - '%d', // team - '%d', // owner - - '%d', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - - '%d', - '%d' - ) ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - return $newID; - - } else { - - #} Failed to Insert - return false; - - } - - } + // if owner = -1, add current + if ( ! isset( $data['owner'] ) || $data['owner'] === -1 ) { + $data['owner'] = zeroBSCRM_user(); + } - return false; + // check action present + legit + if ( ! isset( $data['action'] ) || empty( $data['action'] ) ) { + return false; + } - } + #} ========= / CHECK FIELDS =========== - /** - * deletes a tracking object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteTracking($args=array()){ + #} Check if ID present + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - global $ZBSCRM_t,$wpdb; + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['tracking'], + array( - 'id' => -1 + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $data['owner'], + + // fields + 'zbst_contactid' => $data['contactID'], + 'zbst_action' => $data['action'], + 'zbst_action_detail' => $data['action_detail'], + 'zbst_referrer' => $data['referrer'], + 'zbst_utm_source' => $data['utm_source'], + 'zbst_utm_medium' => $data['utm_medium'], + 'zbst_utm_name' => $data['utm_name'], + 'zbst_utm_term' => $data['utm_term'], + 'zbst_utm_content' => $data['utm_content'], + + 'zbst_lastupdated' => time(), + ), + array( // where + 'ID' => $id, + ), + array( // field data types + '%d', + + '%d', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + + '%d', + ), + array( // where data types + '%d', + ) + ) !== false ) { - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + // Successfully updated - Return id + return $id; - #} Check ID & Delete :) - $id = (int)$id; - return zeroBSCRM_db2_deleteGeneric( $id, 'tracking' ); + } else { - } + // FAILED update + return false; - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_tracking($obj=false){ + } + } else { - $res = false; + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['tracking'], + array( - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - /* - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - */ + // ownership + 'zbs_site' => zeroBSCRM_site(), + 'zbs_team' => zeroBSCRM_team(), + 'zbs_owner' => $data['owner'], + + // fields + 'zbst_contactid' => $data['contactID'], + 'zbst_action' => $data['action'], + 'zbst_action_detail' => $data['action_detail'], + 'zbst_referrer' => $data['referrer'], + 'zbst_utm_source' => $data['utm_source'], + 'zbst_utm_medium' => $data['utm_medium'], + 'zbst_utm_name' => $data['utm_name'], + 'zbst_utm_term' => $data['utm_term'], + 'zbst_utm_content' => $data['utm_content'], + + 'zbst_created' => time(), + 'zbst_lastupdated' => time(), + ), + array( // field data types + '%d', // site + '%d', // team + '%d', // owner + + '%d', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + + '%d', + '%d', + ) + ) > 0 ) { - $res['contactid'] = $obj->zbss_contactid; - $res['action'] = $obj->zbst_action; - $res['action_detail'] = $obj->zbst_action_detail; - $res['referrer'] = $obj->zbst_referrer; - $res['utm_source'] = $obj->zbst_utm_source; - $res['utm_medium'] = $obj->zbst_utm_medium; - $res['utm_name'] = $obj->zbst_utm_name; - $res['utm_term'] = $obj->zbst_utm_term; - $res['utm_content'] = $obj->zbst_utm_content; + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + return $newID; + } else { - $res['created'] = $obj->zbst_created; - $res['lastupdated'] = $obj->zbst_lastupdated; + #} Failed to Insert + return false; - } + } + } - return $res; + return false; + } + /** + * deletes a tracking object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteTracking( $args = array() ) { - } + global $ZBSCRM_t, $wpdb; + #} ============ LOAD ARGS ============= + $defaultArgs = array( - // =========== / Web Tracking (UTM etc.) ==================================== - // =============================================================================== + 'id' => -1, + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ + #} Check ID & Delete :) + $id = (int) $id; + return zeroBSCRM_db2_deleteGeneric( $id, 'tracking' ); + } + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_tracking( $obj = false ) { + + $res = false; + + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + /* + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + */ + + $res['contactid'] = $obj->zbss_contactid; + $res['action'] = $obj->zbst_action; + $res['action_detail'] = $obj->zbst_action_detail; + $res['referrer'] = $obj->zbst_referrer; + $res['utm_source'] = $obj->zbst_utm_source; + $res['utm_medium'] = $obj->zbst_utm_medium; + $res['utm_name'] = $obj->zbst_utm_name; + $res['utm_term'] = $obj->zbst_utm_term; + $res['utm_content'] = $obj->zbst_utm_content; + + $res['created'] = $obj->zbst_created; + $res['lastupdated'] = $obj->zbst_lastupdated; + } + return $res; + } + // =========== / Web Tracking (UTM etc.) ==================================== + // =============================================================================== - // =============================================================================== - // =========== LOGS ========================================================== + // =============================================================================== + // =========== LOGS ========================================================== - /** - * returns cron log lines - * - * @param array $args Associative array of arguments - * searchPhrase, sortByField, sortOrder, page, perPage - * - * @return array of tag lines - */ - public function getCronLogs($args=array()){ + /** + * returns cron log lines + * + * @param array $args Associative array of arguments + * searchPhrase, sortByField, sortOrder, page, perPage + * + * @return array of tag lines + */ + public function getCronLogs( $args = array() ) { // ============ LOAD ARGS ============= $with_notes = true; @@ -6320,1158 +7217,1295 @@ public function getCronLogs($args=array()){ 'with_notes' => true, 'ignoreowner' => false, // this'll let you not-check the owner of obj - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ - - #} ========= / CHECK FIELDS =========== + #} ========= / CHECK FIELDS =========== - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['cronmanagerlogs']; + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['cronmanagerlogs']; - #} ============= WHERE ================ + #} ============= WHERE ================ - #} job - if (!empty($job) && $job > 0) $wheres['job'] = array('job','=','%s',$job); + #} job + if ( ! empty( $job ) && $job > 0 ) { + $wheres['job'] = array( 'job', '=', '%s', $job ); + } if ( $with_notes ) { $wheres['notes'] = array( 'jobnotes', '<>', '%s', '' ); } - #} ============ / WHERE =============== + #} ============ / WHERE =============== - #} Build out any WHERE clauses - $wheresArr= $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership - - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - try { + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + try { - } catch (Exception $e){ + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - #} General SQL Err - $this->catchSQLError($e); + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + } - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $resArr = $this->tidy_cronlog($resDataLine); + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - $res[] = $resArr; + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - } - } + // tidy + $resArr = $this->tidy_cronlog( $resDataLine ); - return $res; - } + $res[] = $resArr; + } + } + return $res; + } - /** - * adds or updates a cron log object - * - * @param array $args Associative array of arguments - * id (not req.), owner (not req.) data -> key/val - * - * @return int line ID - */ - public function addUpdateCronLog($args=array()){ + /** + * adds or updates a cron log object + * + * @param array $args Associative array of arguments + * id (not req.), owner (not req.) data -> key/val + * + * @return int line ID + */ + public function addUpdateCronLog( $args = array() ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; - #} ============ LOAD ARGS ============= - $defaultArgs = array( + #} ============ LOAD ARGS ============= + $defaultArgs = array( - 'id' => -1, - 'owner' => -1, + 'id' => -1, + 'owner' => -1, - // fields (directly) - 'data' => array( + // fields (directly) + 'data' => array( - 'job' => '', - 'jobstatus' => -1, - 'jobstarted' => -1, - 'jobfinished' => -1, - 'jobnotes' => '' - - ) + 'job' => '', + 'jobstatus' => -1, + 'jobstarted' => -1, + 'jobfinished' => -1, + 'jobnotes' => '', - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ + ), + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - #} ========== CHECK FIELDS ============ + #} ========== CHECK FIELDS ============ - $id = (int)$id; + $id = (int) $id; // if owner = -1, add current if ( $owner === -1 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable $owner = zeroBSCRM_user(); } - #} ========= / CHECK FIELDS =========== - - $dataArr = array( - - // ownership - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => $owner, - - // fields - 'job' => $data['job'], - 'jobstatus' => $data['jobstatus'], - 'jobstarted' => $data['jobstarted'], - 'jobfinished' => $data['jobfinished'], - 'jobnotes' => $data['jobnotes'] - ); - - $dataTypes = array( // field data types - '%d', - - '%s', - '%d', - '%d', - '%d', - '%s' - ); - - - if (isset($id) && !empty($id) && $id > 0){ - - #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['cronmanagerlogs'], - $dataArr, - array( // where - 'ID' => $id - ), - $dataTypes, - array( // where data types - '%d' - )) !== false){ - - // Successfully updated - Return id - return $id; - - } else { - - // FAILED update - return false; - - } - - } else { - - // add team etc - $dataArr['zbs_site'] = zeroBSCRM_site(); $dataTypes[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); $dataTypes[] = '%d'; - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['cronmanagerlogs'], - $dataArr, - $dataTypes ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - - return $newID; - - } else { - - #} Failed to Insert - return false; - - } - - } - - return false; - - } - - /** - * deletes a CRON Log object - * NOTE! this doesn't yet delete any META! - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteCronLog($args=array()){ - - global $ZBSCRM_t,$wpdb; - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - 'id' => -1 - - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============ - - #} Check ID & Delete :) - $id = (int)$id; - return zeroBSCRM_db2_deleteGeneric( $id, 'cronmanagerlogs' ); - - } - - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - private function tidy_cronlog($obj=false){ - - $res = false; - - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - $res['owner'] = $obj->zbs_owner; - - $res['job'] = $obj->job; - $res['jobstatus'] = $obj->jobstatus; - $res['jobstarted'] = $obj->jobstarted; - $res['jobfinished'] = $obj->jobfinished; - $res['jobnotes'] = $obj->jobnotes; - - } - - return $res; - - - } - - // =========== / CRONLOGS ======================================================= - // =============================================================================== - - // =============================================================================== - // ============= GENERIC ======================================================== - - - /** - * Wrapper function for emptying tables (use with care) - * ... can only truncate tables in our ZBSCRM_t - * - * @param string $tableKey (refers to ZBSCRM_t global) - * - * @return result - */ - public function truncate($tableKey=''){ + #} ========= / CHECK FIELDS =========== - global $ZBSCRM_t; + $dataArr = array( - if (is_string($tableKey) && !empty($tableKey) && isset($ZBSCRM_t[$tableKey])){ - - global $wpdb; - return $wpdb->query("TRUNCATE TABLE `".$ZBSCRM_t[$tableKey]."`"); + // ownership + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => $owner, - } - - return false; - - } - - // =========== / GENERIC ======================================================== - // =============================================================================== - - - // =============================================================================== - // =========== FIELD HELPERS =============================================== - - - /** - * Returns a field from an object model if it exists - * - * @param CRM_TYPE int object_type_id - object type ID - * @param string field_key - key of field (e.g. `status`) - * - * @return bool|array - field type info (as per direct from the object_model) - */ - public function get_model_field_info( $object_type_id = -1, $field_key = ''){ - - // valid obj type id and key? - if ( $this->isValidObjTypeID( $object_type_id ) && !empty( $field_key ) ){ - - // get object layer and load object model - $object_layer = $this->getObjectLayerByType( $object_type_id ); - if ( $object_layer ){ - - $object_model = $object_layer->objModel( true ); - - // if set, return - if ( is_array( $object_model ) && isset( $object_model[ $field_key ] ) ){ - - return $object_model[ $field_key ]; - - } - - } - - - // as a temporary workaround until we have addresses loaded from DAL3 - // check address field presence via global - if ( $object_type_id == ZBS_TYPE_ADDRESS ){ - - // effectively returns $zbsAddressFields: - $obj_model_global = $this->get_object_field_global( ZBS_TYPE_ADDRESS ); - - if ( isset( $obj_model_global[ $field_key ] ) ){ - - // As an aside, the $potential_field format will be different here - // as this takes from the globals model, not the DAL model - // ... please bear this in mind if interacting with address fields this way - return $obj_model_global[ $field_key ]; - - } - - - } - - - } - - return false; - - } - - /** - * Returns true if a field from an object model exists - * - * @param CRM_TYPE int object_type_id - object type ID - * @param string field_key - key of field (e.g. `status`) - * - * @return bool - does field exist - */ - public function does_model_field_exist( $object_type_id = -1, $field_key = ''){ - - // valid obj type id and key? - if ( $this->isValidObjTypeID( $object_type_id ) && !empty( $field_key ) ){ + // fields + 'job' => $data['job'], + 'jobstatus' => $data['jobstatus'], + 'jobstarted' => $data['jobstarted'], + 'jobfinished' => $data['jobfinished'], + 'jobnotes' => $data['jobnotes'], + ); - // Check for field existence - $potential_field = $this->get_model_field_info( $object_type_id, $field_key ); + $dataTypes = array( // field data types + '%d', - if ( $potential_field !== false ){ + '%s', + '%d', + '%d', + '%d', + '%s', + ); - // found it - return true; + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - } + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['cronmanagerlogs'], + $dataArr, + array( // where + 'ID' => $id, + ), + $dataTypes, + array( // where data types + '%d', + ) + ) !== false ) { - } + // Successfully updated - Return id + return $id; - return false; + } else { - } + // FAILED update + return false; - // =========== / FIELD HELPERS =============================================== - // =============================================================================== + } + } else { + // add team etc + $dataArr['zbs_site'] = zeroBSCRM_site(); + $dataTypes[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $dataTypes[] = '%d'; + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['cronmanagerlogs'], + $dataArr, + $dataTypes + ) > 0 ) { -/* ====================================================== - / DAL CRUD - ====================================================== */ + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + return $newID; + } else { + #} Failed to Insert + return false; + } + } -/* ====================================================== - Formatters (Generic) - ====================================================== */ + return false; + } - // legacy signpost, this is now overwritten by DAL->contacts->fullname - public function format_fullname( $contactArr=array() ){ + /** + * deletes a CRON Log object + * NOTE! this doesn't yet delete any META! + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteCronLog( $args = array() ) { - return $this->contacts->format_fullname( $contactArr ); - } + global $ZBSCRM_t, $wpdb; - // legacy signpost, this is now overwritten by DAL->[contacts|companies]->format_name_etc - public function format_name_etc( $objectArr=array(), $args=array() ){ + #} ============ LOAD ARGS ============= + $defaultArgs = array( - #} =========== LOAD ARGS ============== - $defaultArgs = array( + 'id' => -1, - 'incFirstLineAddr' => false, - 'incID' => false, - 'company' => false, // if true, looks for 'name' not 'fname+lname' + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============ - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} Check ID & Delete :) + $id = (int) $id; + return zeroBSCRM_db2_deleteGeneric( $id, 'cronmanagerlogs' ); + } - if ( !$company ) - return $this->contacts->format_name_etc( $objectArr, $args ); - else - return $this->companies->format_name_etc( $objectArr, $args ); + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + private function tidy_cronlog( $obj = false ) { - } + $res = false; - /** - * Returns a formatted address - * via getContactFullName this replaces zeroBS_customerAddr in dal1 - * NOTE, post v3.0 applies to ANY form of addr. - * - * @param array $obj (tidied db obj) - * - * @return string address - */ - public function format_address($contactArr=array(),$args=array()){ + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + $res['owner'] = $obj->zbs_owner; - #} =========== LOAD ARGS ============== - $defaultArgs = array( + $res['job'] = $obj->job; + $res['jobstatus'] = $obj->jobstatus; + $res['jobstarted'] = $obj->jobstarted; + $res['jobfinished'] = $obj->jobfinished; + $res['jobnotes'] = $obj->jobnotes; - 'addrFormat' => 'short', - 'delimiter' => ', ', // could use
- 'secondaddr' => false // if true, use second address (if present in contact_arr) + } + return $res; + } + // =========== / CRONLOGS ======================================================= + // =============================================================================== - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + // =============================================================================== + // ============= GENERIC ======================================================== - $ret = ''; $fieldPrefix = ''; - if ($secondaddr) $fieldPrefix = 'sec'; - // v3.0 exception, contacts need this prefix for second :/ - // attempt to account for that: - if ($secondaddr && !isset($contactArr[$fieldPrefix.'addr1']) && isset($contactArr['secaddr_'.'addr1'])) $fieldPrefix = 'secaddr_'; + /** + * Wrapper function for emptying tables (use with care) + * ... can only truncate tables in our ZBSCRM_t + * + * @param string $tableKey (refers to ZBSCRM_t global) + * + * @return result + */ + public function truncate( $tableKey = '' ) { + global $ZBSCRM_t; - #} Legacy from DAL1: - $addrCustomFields = $this->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); + if ( is_string( $tableKey ) && ! empty( $tableKey ) && isset( $ZBSCRM_t[ $tableKey ] ) ) { - if ($addrFormat == 'short'){ + global $wpdb; + return $wpdb->query( 'TRUNCATE TABLE `' . $ZBSCRM_t[ $tableKey ] . '`' ); - if (isset($contactArr[$fieldPrefix.'addr1']) && !empty($contactArr[$fieldPrefix.'addr1'])) $ret = $contactArr[$fieldPrefix.'addr1']; - if (isset($contactArr[$fieldPrefix.'city']) && !empty($contactArr[$fieldPrefix.'city'])) $ret .= $this->delimiterIf($delimiter,$ret).$contactArr[$fieldPrefix.'city']; + } - } else if ($addrFormat == 'full'){ + return false; + } - if (isset($contactArr[$fieldPrefix.'addr1']) && !empty($contactArr[$fieldPrefix.'addr1'])) $ret = $contactArr[$fieldPrefix.'addr1']; - if (isset($contactArr[$fieldPrefix.'addr2']) && !empty($contactArr[$fieldPrefix.'addr2'])) $ret .= $this->delimiterIf($delimiter,$ret).$contactArr[$fieldPrefix.'addr2']; - if (isset($contactArr[$fieldPrefix.'city']) && !empty($contactArr[$fieldPrefix.'city'])) $ret .= $this->delimiterIf($delimiter,$ret).$contactArr[$fieldPrefix.'city']; - if (isset($contactArr[$fieldPrefix.'county']) && !empty($contactArr[$fieldPrefix.'county'])) $ret .= $this->delimiterIf($delimiter,$ret).$contactArr[$fieldPrefix.'county']; - if (isset($contactArr[$fieldPrefix.'postcode']) && !empty($contactArr[$fieldPrefix.'postcode'])) $ret .= $this->delimiterIf($delimiter,$ret).$contactArr[$fieldPrefix.'postcode']; - if (isset($contactArr[$fieldPrefix.'country']) && !empty($contactArr[$fieldPrefix.'country']) && zeroBSCRM_getSetting('countries') == 1) $ret .= $this->delimiterIf($delimiter,$ret).$contactArr[$fieldPrefix.'country']; + // =========== / GENERIC ======================================================== + // =============================================================================== - // any custom fields here - if (is_array($addrCustomFields) && count($addrCustomFields) > 0){ + // =============================================================================== + // =========== FIELD HELPERS =============================================== - foreach ($addrCustomFields as $cK => $cF){ + /** + * Returns a field from an object model if it exists + * + * @param CRM_TYPE int object_type_id - object type ID + * @param string field_key - key of field (e.g. `status`) + * + * @return bool|array - field type info (as per direct from the object_model) + */ + public function get_model_field_info( $object_type_id = -1, $field_key = '' ) { - // v2: - //$cKN = (int)$cK+1; - //$cKey = $fieldPrefix.'addr_cf'.$cKN; - // v3: - $cKey = ($secondaddr) ? 'secaddr_'.$cK : 'addr_'.$cK; + // valid obj type id and key? + if ( $this->isValidObjTypeID( $object_type_id ) && ! empty( $field_key ) ) { - if (isset($contactArr[$cKey]) && !empty($contactArr[$cKey])) { + // get object layer and load object model + $object_layer = $this->getObjectLayerByType( $object_type_id ); + if ( $object_layer ) { - // if someone is using date custom fields here, output date, not uts - super edge case gh-349 - if (isset($contactArr[$cKey.'_cfdate']) && !empty($contactArr[$cKey.'_cfdate'])) - $ret .= $this->delimiterIf($delimiter,$ret).$contactArr[$cKey.'_cfdate']; - else - $ret .= $this->delimiterIf($delimiter,$ret).$contactArr[$cKey]; + $object_model = $object_layer->objModel( true ); - } - } + // if set, return + if ( is_array( $object_model ) && isset( $object_model[ $field_key ] ) ) { - } + return $object_model[ $field_key ]; + } + } - } + // as a temporary workaround until we have addresses loaded from DAL3 + // check address field presence via global + if ( $object_type_id == ZBS_TYPE_ADDRESS ) { - $trimRet = trim($ret); - return $trimRet; - } + // effectively returns $zbsAddressFields: + $obj_model_global = $this->get_object_field_global( ZBS_TYPE_ADDRESS ); - public function makeSlug($string, $replace = array(), $delimiter = '-') { + if ( isset( $obj_model_global[ $field_key ] ) ) { - // NOTE: the following can likely be replaced with sanitize_title - // https://wordpress.stackexchange.com/questions/74415/how-does-wordpress-generate-url-slugs - //return sanitize_title(sanitize_title($string, '', 'save'), '', 'query'); + // As an aside, the $potential_field format will be different here + // as this takes from the globals model, not the DAL model + // ... please bear this in mind if interacting with address fields this way + return $obj_model_global[ $field_key ]; - // https://github.com/phalcon/incubator/blob/master/Library/Phalcon/Utils/Slug.php - // and - // https://stackoverflow.com/questions/4910627/php-iconv-translit-for-removing-accents-not-working-as-excepted - //if (!extension_loaded('iconv')) { - // throw new Exception('iconv module not loaded'); - //} - // Save the old locale and set the new locale to UTF-8 - $oldLocale = setlocale(LC_ALL, '0'); - setlocale(LC_ALL, 'en_US.UTF-8'); + } + } + } - // replace non letter or digits by - - $clean = preg_replace('#[^\\pL\d]+#u', '-', $string); + return false; + } - // transliterate - if (function_exists('iconv')) - $clean = @iconv('UTF-8', 'ASCII//TRANSLIT', $clean); - // else? smt else? + /** + * Returns true if a field from an object model exists + * + * @param CRM_TYPE int object_type_id - object type ID + * @param string field_key - key of field (e.g. `status`) + * + * @return bool - does field exist + */ + public function does_model_field_exist( $object_type_id = -1, $field_key = '' ) { - // replace - if (!empty($replace)) { - $clean = str_replace((array) $replace, ' ', $clean); - } - - // clean - $clean = $this->makeSlugCleanStr($clean,$delimiter); + // valid obj type id and key? + if ( $this->isValidObjTypeID( $object_type_id ) && ! empty( $field_key ) ) { - // Revert back to the old locale - setlocale(LC_ALL, $oldLocale); - return $clean; - } + // Check for field existence + $potential_field = $this->get_model_field_info( $object_type_id, $field_key ); - private function makeSlugCleanStr($string='', $delimiter='-'){ + if ( $potential_field !== false ) { - // fix for ascii passing (I think) of ' resulting in -039- in place of ' - $string = str_replace('-039-','',$string); + // found it + return true; - // replace non letter or non digits by - - $string = preg_replace('#[^\pL\d]+#u', '-', $string); - // Trim trailing - - $string = trim($string, '-'); - $clean = preg_replace('~[^-\w]+~', '', $string); - $clean = strtolower($clean); - $clean = preg_replace('#[\/_|+ -]+#', $delimiter, $clean); - $clean = trim($clean, $delimiter); + } + } + return false; + } - return $clean; - } + // =========== / FIELD HELPERS =============================================== + // =============================================================================== + /* + ====================================================== + / DAL CRUD + ====================================================== */ -/* ====================================================== - / Formatters - ====================================================== */ + /* + ====================================================== + Formatters (Generic) + ====================================================== */ + // legacy signpost, this is now overwritten by DAL->contacts->fullname + public function format_fullname( $contactArr = array() ) { + return $this->contacts->format_fullname( $contactArr ); + } + // legacy signpost, this is now overwritten by DAL->[contacts|companies]->format_name_etc + public function format_name_etc( $objectArr = array(), $args = array() ) { + #} =========== LOAD ARGS ============== + $defaultArgs = array( + 'incFirstLineAddr' => false, + 'incID' => false, + 'company' => false, // if true, looks for 'name' not 'fname+lname' -/* ====================================================== - To be sorted helpers - ====================================================== */ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - /** - * helper - returns single field against db table WHERE X - * Will only work for native fields (not Cutom fields) - * - * @param array WHERE clauses (not Req.) - * @param string tablename - * @param string colname - * - * @return string - */ - public function getFieldByWHERE($args=array()){ + if ( ! $company ) { + return $this->contacts->format_name_etc( $objectArr, $args ); + } else { + return $this->companies->format_name_etc( $objectArr, $args ); + } + } - #} =========== LOAD ARGS ============== - $defaultArgs = array( + /** + * Returns a formatted address + * via getContactFullName this replaces zeroBS_customerAddr in dal1 + * NOTE, post v3.0 applies to ANY form of addr. + * + * @param array $obj (tidied db obj) + * + * @return string address + */ + public function format_address( $contactArr = array(), $args = array() ) { - 'where' => -1, - 'objtype' => -1, - 'colname' => '', + #} =========== LOAD ARGS ============== + $defaultArgs = array( - // permissions - 'ignoreowner' => false // this'll let you not-check the owner of obj + 'addrFormat' => 'short', + 'delimiter' => ', ', // could use
+ 'secondaddr' => false, // if true, use second address (if present in contact_arr) - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} ========== CHECK FIELDS ============ + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - // check obtype is legit - $objtype = (int)$objtype; - if (!isset($objtype) || $objtype == -1 || $this->objTypeKey($objtype) === -1) return false; - - // check field (or 'COUNT(x)') - if (empty($colname)) return false; + $ret = ''; + $fieldPrefix = ''; + if ( $secondaddr ) { + $fieldPrefix = 'sec'; + } + // v3.0 exception, contacts need this prefix for second :/ + // attempt to account for that: + if ( $secondaddr && ! isset( $contactArr[ $fieldPrefix . 'addr1' ] ) && isset( $contactArr[ 'secaddr_' . 'addr1' ] ) ) { + $fieldPrefix = 'secaddr_'; + } - #} ========= / CHECK FIELDS =========== + #} Legacy from DAL1: + $addrCustomFields = $this->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + if ( $addrFormat == 'short' ) { - #} Build query - NOTE this is vulnerable to injection. - $query = "SELECT $colname FROM ".$this->lazyTable($objtype); - //$params[] = $colname; + if ( isset( $contactArr[ $fieldPrefix . 'addr1' ] ) && ! empty( $contactArr[ $fieldPrefix . 'addr1' ] ) ) { + $ret = $contactArr[ $fieldPrefix . 'addr1' ]; + } + if ( isset( $contactArr[ $fieldPrefix . 'city' ] ) && ! empty( $contactArr[ $fieldPrefix . 'city' ] ) ) { + $ret .= $this->delimiterIf( $delimiter, $ret ) . $contactArr[ $fieldPrefix . 'city' ]; + } + } elseif ( $addrFormat == 'full' ) { - #} ============= WHERE ================ + if ( isset( $contactArr[ $fieldPrefix . 'addr1' ] ) && ! empty( $contactArr[ $fieldPrefix . 'addr1' ] ) ) { + $ret = $contactArr[ $fieldPrefix . 'addr1' ]; + } + if ( isset( $contactArr[ $fieldPrefix . 'addr2' ] ) && ! empty( $contactArr[ $fieldPrefix . 'addr2' ] ) ) { + $ret .= $this->delimiterIf( $delimiter, $ret ) . $contactArr[ $fieldPrefix . 'addr2' ]; + } + if ( isset( $contactArr[ $fieldPrefix . 'city' ] ) && ! empty( $contactArr[ $fieldPrefix . 'city' ] ) ) { + $ret .= $this->delimiterIf( $delimiter, $ret ) . $contactArr[ $fieldPrefix . 'city' ]; + } + if ( isset( $contactArr[ $fieldPrefix . 'county' ] ) && ! empty( $contactArr[ $fieldPrefix . 'county' ] ) ) { + $ret .= $this->delimiterIf( $delimiter, $ret ) . $contactArr[ $fieldPrefix . 'county' ]; + } + if ( isset( $contactArr[ $fieldPrefix . 'postcode' ] ) && ! empty( $contactArr[ $fieldPrefix . 'postcode' ] ) ) { + $ret .= $this->delimiterIf( $delimiter, $ret ) . $contactArr[ $fieldPrefix . 'postcode' ]; + } + if ( isset( $contactArr[ $fieldPrefix . 'country' ] ) && ! empty( $contactArr[ $fieldPrefix . 'country' ] ) && zeroBSCRM_getSetting( 'countries' ) == 1 ) { + $ret .= $this->delimiterIf( $delimiter, $ret ) . $contactArr[ $fieldPrefix . 'country' ]; + } - #} Add any where's - $wheres = $where; + // any custom fields here + if ( is_array( $addrCustomFields ) && count( $addrCustomFields ) > 0 ) { - #} ============ / WHERE ============== + foreach ( $addrCustomFields as $cK => $cF ) { - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + // v2: + // $cKN = (int)$cK+1; + // $cKey = $fieldPrefix.'addr_cf'.$cKN; + // v3: + $cKey = ( $secondaddr ) ? 'secaddr_' . $cK : 'addr_' . $cK; - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + if ( isset( $contactArr[ $cKey ] ) && ! empty( $contactArr[ $cKey ] ) ) { - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + // if someone is using date custom fields here, output date, not uts - super edge case gh-349 + if ( isset( $contactArr[ $cKey . '_cfdate' ] ) && ! empty( $contactArr[ $cKey . '_cfdate' ] ) ) { + $ret .= $this->delimiterIf( $delimiter, $ret ) . $contactArr[ $cKey . '_cfdate' ]; + } else { + $ret .= $this->delimiterIf( $delimiter, $ret ) . $contactArr[ $cKey ]; + } + } + } + } + } - try { + $trimRet = trim( $ret ); + return $trimRet; + } - #} Prep & run query - $queryObj = $this->prepare($query,$params); - return $wpdb->get_var($queryObj); + public function makeSlug( $string, $replace = array(), $delimiter = '-' ) { - } catch (Exception $e){ + // NOTE: the following can likely be replaced with sanitize_title + // https://wordpress.stackexchange.com/questions/74415/how-does-wordpress-generate-url-slugs + // return sanitize_title(sanitize_title($string, '', 'save'), '', 'query'); - #} General SQL Err - $this->catchSQLError($e); + // https://github.com/phalcon/incubator/blob/master/Library/Phalcon/Utils/Slug.php + // and + // https://stackoverflow.com/questions/4910627/php-iconv-translit-for-removing-accents-not-working-as-excepted + // if (!extension_loaded('iconv')) { + // throw new Exception('iconv module not loaded'); + // } + // Save the old locale and set the new locale to UTF-8 + $oldLocale = setlocale( LC_ALL, '0' ); + setlocale( LC_ALL, 'en_US.UTF-8' ); - } + // replace non letter or digits by - + $clean = preg_replace( '#[^\\pL\d]+#u', '-', $string ); + // transliterate + if ( function_exists( 'iconv' ) ) { + $clean = @iconv( 'UTF-8', 'ASCII//TRANSLIT', $clean ); + } + // else? smt else? - return false; + // replace + if ( ! empty( $replace ) ) { + $clean = str_replace( (array) $replace, ' ', $clean ); + } - } + // clean + $clean = $this->makeSlugCleanStr( $clean, $delimiter ); + // Revert back to the old locale + setlocale( LC_ALL, $oldLocale ); + return $clean; + } - /** - * helper - returns single field against db table (where ID =) - * Will only work for native fields (not Cutom fields) - * - * @param int objID object id - * @param int objTypeID objectType id - * @param string colname - * - * @return string - */ - public function getFieldByID($args=array()){ + private function makeSlugCleanStr( $string = '', $delimiter = '-' ) { - #} =========== LOAD ARGS ============== - $defaultArgs = array( + // fix for ascii passing (I think) of ' resulting in -039- in place of ' + $string = str_replace( '-039-', '', $string ); - 'id' => -1, - 'objtype' => -1, - 'colname' => '', + // replace non letter or non digits by - + $string = preg_replace( '#[^\pL\d]+#u', '-', $string ); + // Trim trailing - + $string = trim( $string, '-' ); + $clean = preg_replace( '~[^-\w]+~', '', $string ); + $clean = strtolower( $clean ); + $clean = preg_replace( '#[\/_|+ -]+#', $delimiter, $clean ); + $clean = trim( $clean, $delimiter ); - // permissions - 'ignoreowner' => false // this'll let you not-check the owner of obj + return $clean; + } - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - #} ========== CHECK FIELDS ============ + /* + ====================================================== + / Formatters + ====================================================== */ + + /* + ====================================================== + To be sorted helpers + ====================================================== */ + + /** + * helper - returns single field against db table WHERE X + * Will only work for native fields (not Cutom fields) + * + * @param array WHERE clauses (not Req.) + * @param string tablename + * @param string colname + * + * @return string + */ + public function getFieldByWHERE( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( - // check id - $id = (int)$id; - if (!isset($id) || $id < 1) return false; + 'where' => -1, + 'objtype' => -1, + 'colname' => '', - // check obtype is legit - $objtype = (int)$objtype; - if (!isset($objtype) || $objtype == -1 || $this->objTypeKey($objtype) === -1) return false; - - // check field - if (empty($colname)) return false; + // permissions + 'ignoreowner' => false, // this'll let you not-check the owner of obj - #} ========= / CHECK FIELDS =========== + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + #} ========== CHECK FIELDS ============ - #} Build query - NOTE this is vulnerable to injection. - $query = "SELECT $colname FROM ".$this->lazyTable($objtype); - //$params[] = $colname; + // check obtype is legit + $objtype = (int) $objtype; + if ( ! isset( $objtype ) || $objtype == -1 || $this->objTypeKey( $objtype ) === -1 ) { + return false; + } - #} ============= WHERE ================ + // check field (or 'COUNT(x)') + if ( empty( $colname ) ) { + return false; + } - // Add ID - $wheres['ID'] = array( 'ID', '=', '%d', $id ); + #} ========= / CHECK FIELDS =========== + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} ============ / WHERE ============== + #} Build query - NOTE this is vulnerable to injection. + $query = "SELECT $colname FROM " . $this->lazyTable( $objtype ); + // $params[] = $colname; - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} ============= WHERE ================ - #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner - $params = array_merge($params,$this->ownershipQueryVars($ignoreowner)); // merges in any req. - $ownQ = $this->ownershipSQL($ignoreowner); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query - #} / Ownership + #} Add any where's + $wheres = $where; - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort('ID','DESC') . $this->buildPaging(0,1); + #} ============ / WHERE ============== - try { + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - #} Prep & run query - $queryObj = $this->prepare($query,$params); - return $wpdb->get_var($queryObj); + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - } catch (Exception $e){ + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - #} General SQL Err - $this->catchSQLError($e); + try { - } + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + return $wpdb->get_var( $queryObj ); + } catch ( Exception $e ) { - return false; + #} General SQL Err + $this->catchSQLError( $e ); - } + } + return false; + } - /** - * helper - forces update of field for obj id + type, - * THIS IS HARD usage, not for beginners/non-directors. - * ... can break things if using this, so only use strictly for globally generic columns - * ... e.g. zbs_owner, which appears in all obj. - * ... ALWAYS use the DAL->contacts->whatever before this, where possible - * // NOTE NOTE - THIS does not update "lastupdated" for each obj... AVOID USE! - * - * @param int objID object id - * @param int objTypeID objectType id - * @param string colname - * - * @return string - */ - public function setFieldByID($args=array()){ + /** + * helper - returns single field against db table (where ID =) + * Will only work for native fields (not Cutom fields) + * + * @param int objID object id + * @param int objTypeID objectType id + * @param string colname + * + * @return string + */ + public function getFieldByID( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( - #} =========== LOAD ARGS ============== - $defaultArgs = array( + 'id' => -1, + 'objtype' => -1, + 'colname' => '', - 'objID' => -1, - 'objTypeID' => -1, + // permissions + 'ignoreowner' => false, // this'll let you not-check the owner of obj - 'colname' => '', - 'coldatatype' => '%d', // %d/s - 'newValue' => -99, + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= + #} ========== CHECK FIELDS ============ - // this'll only update columnames present in here: - $restrictedToColumns = array('zbs_owner'); + // check id + $id = (int) $id; + if ( ! isset( $id ) || $id < 1 ) { + return false; + } - if (in_array($colname,$restrictedToColumns) && $objID > 0 && $objTypeID > 0 && !empty($colname) && !empty($coldatatype) && $newValue !== -99){ + // check obtype is legit + $objtype = (int) $objtype; + if ( ! isset( $objtype ) || $objtype == -1 || $this->objTypeKey( $objtype ) === -1 ) { + return false; + } - global $wpdb; + // check field + if ( empty( $colname ) ) { + return false; + } - // got table? - $tableName = $this->lazyTable($objTypeID); + #} ========= / CHECK FIELDS =========== - if (empty($tableName)) return false; + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} Attempt update - if ($wpdb->update( - $tableName, - array( + #} Build query - NOTE this is vulnerable to injection. + $query = "SELECT $colname FROM " . $this->lazyTable( $objtype ); + // $params[] = $colname; - $colname => $newValue + #} ============= WHERE ================ - ), - array( // where - 'ID' => $objID - ), - array( // field data types - $coldatatype - ), - array( // where data types - '%d' - )) !== false){ + // Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - // Successfully updated - Return id - return $objID; + #} ============ / WHERE ============== - } else { + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - // FAILED update - return false; + #} Ownership v1.0 - the following adds SITE + TEAM checks, and (optionally), owner + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner ); + if ( ! empty( $ownQ ) ) { + $additionalWhere = $this->spaceAnd( $additionalWhere ) . $ownQ; // adds str to query + } + #} / Ownership - } + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); + try { - } + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + return $wpdb->get_var( $queryObj ); + } catch ( Exception $e ) { - return false; - - } - + #} General SQL Err + $this->catchSQLError( $e ); + } + return false; + } + /** + * helper - forces update of field for obj id + type, + * THIS IS HARD usage, not for beginners/non-directors. + * ... can break things if using this, so only use strictly for globally generic columns + * ... e.g. zbs_owner, which appears in all obj. + * ... ALWAYS use the DAL->contacts->whatever before this, where possible + * // NOTE NOTE - THIS does not update "lastupdated" for each obj... AVOID USE! + * + * @param int objID object id + * @param int objTypeID objectType id + * @param string colname + * + * @return string + */ + public function setFieldByID( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + 'objID' => -1, + 'objTypeID' => -1, + 'colname' => '', + 'coldatatype' => '%d', // %d/s + 'newValue' => -99, + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + // this'll only update columnames present in here: + $restrictedToColumns = array( 'zbs_owner' ); + if ( in_array( $colname, $restrictedToColumns ) && $objID > 0 && $objTypeID > 0 && ! empty( $colname ) && ! empty( $coldatatype ) && $newValue !== -99 ) { - // brutal switch for lazy tablenames - public function lazyTable($objType=-1){ + global $wpdb; - global $ZBSCRM_t; + // got table? + $tableName = $this->lazyTable( $objTypeID ); - switch ($objType){ + if ( empty( $tableName ) ) { + return false; + } - case ZBS_TYPE_CONTACT: - return $ZBSCRM_t['contacts']; - break; - // dal3: - case ZBS_TYPE_COMPANY: - return $ZBSCRM_t['companies']; - break; - case ZBS_TYPE_QUOTE: - return $ZBSCRM_t['quotes']; - break; - case ZBS_TYPE_INVOICE: - return $ZBSCRM_t['invoices']; - break; - case ZBS_TYPE_TRANSACTION: - return $ZBSCRM_t['transactions']; - break; - case ZBS_TYPE_TASK: - return $ZBSCRM_t['events']; - break; - case ZBS_TYPE_FORM: - return $ZBSCRM_t['forms']; - break; - case ZBS_TYPE_LOG: - return $ZBSCRM_t['logs']; - break; - case ZBS_TYPE_SEGMENT: - return $ZBSCRM_t['segments']; - break; - case ZBS_TYPE_LINEITEM: - return $ZBSCRM_t['lineitems']; - break; - case ZBS_TYPE_TASK_REMINDER: - return $ZBSCRM_t['eventreminders']; - break; - case ZBS_TYPE_QUOTETEMPLATE: - return $ZBSCRM_t['quotetemplates']; - break; + #} Attempt update + if ( $wpdb->update( + $tableName, + array( - } - - return false; + $colname => $newValue, + + ), + array( // where + 'ID' => $objID, + ), + array( // field data types + $coldatatype, + ), + array( // where data types + '%d', + ) + ) !== false ) { - } + // Successfully updated - Return id + return $objID; - // brutal switch for lazy tidy func - public function lazyTidy($objType=-1,$obj=false){ + } else { - switch ($objType){ + // FAILED update + return false; - case ZBS_TYPE_CONTACT: - return $this->contacts->tidy_contact($obj); - break; - // dal3: - case ZBS_TYPE_COMPANY: - return $this->companies->tidy_company($obj); - break; - case ZBS_TYPE_QUOTE: - return $this->quotes->tidy_quote($obj); - break; - case ZBS_TYPE_INVOICE: - return $this->invoices->tidy_invoice($obj); - break; - case ZBS_TYPE_TRANSACTION: - return $this->transactions->tidy_transaction($obj); - break; - case ZBS_TYPE_TASK: - return $this->events->tidy_event($obj); - break; - case ZBS_TYPE_FORM: - return $this->forms->tidy_form($obj); - break; - case ZBS_TYPE_LOG: - return $this->logs->tidy_log($obj); - break; - case ZBS_TYPE_SEGMENT: - return $this->segments->tidy_segment($obj); - break; - case ZBS_TYPE_LINEITEM: - return $this->lineitems->tidy_lineitem($obj); - break; - case ZBS_TYPE_TASK_REMINDER: - return $this->eventreminders->tidy_eventreminder($obj); - break; - case ZBS_TYPE_QUOTETEMPLATE: - return $this->quotetemplates->tidy_quotetemplate($obj); - break; + } + } + return false; + } - } - - return false; + // brutal switch for lazy tablenames + public function lazyTable( $objType = -1 ) { - } - - // guesses at a tidy... lazy, remove these if hit walls - public function lazyTidyGeneric($obj=false){ - - $res = false; - - foreach ($obj as $propKey => $prop){ - - if (!is_array($res)) $res = array(); + global $ZBSCRM_t; - if ($propKey != 'ID' && strpos($propKey, '_') > 0){ + switch ( $objType ) { - // zbs_owner -> owner - $newKey = substr($propKey,strpos($propKey, '_')+1); - - $res[$newKey] = $this->stripSlashes($prop); + case ZBS_TYPE_CONTACT: + return $ZBSCRM_t['contacts']; + break; + // dal3: + case ZBS_TYPE_COMPANY: + return $ZBSCRM_t['companies']; + break; + case ZBS_TYPE_QUOTE: + return $ZBSCRM_t['quotes']; + break; + case ZBS_TYPE_INVOICE: + return $ZBSCRM_t['invoices']; + break; + case ZBS_TYPE_TRANSACTION: + return $ZBSCRM_t['transactions']; + break; + case ZBS_TYPE_TASK: + return $ZBSCRM_t['events']; + break; + case ZBS_TYPE_FORM: + return $ZBSCRM_t['forms']; + break; + case ZBS_TYPE_LOG: + return $ZBSCRM_t['logs']; + break; + case ZBS_TYPE_SEGMENT: + return $ZBSCRM_t['segments']; + break; + case ZBS_TYPE_LINEITEM: + return $ZBSCRM_t['lineitems']; + break; + case ZBS_TYPE_TASK_REMINDER: + return $ZBSCRM_t['eventreminders']; + break; + case ZBS_TYPE_QUOTETEMPLATE: + return $ZBSCRM_t['quotetemplates']; + break; - } else $res['id'] = $prop; + } + return false; + } - } + // brutal switch for lazy tidy func + public function lazyTidy( $objType = -1, $obj = false ) { - return $res; + switch ( $objType ) { - } + case ZBS_TYPE_CONTACT: + return $this->contacts->tidy_contact( $obj ); + break; + // dal3: + case ZBS_TYPE_COMPANY: + return $this->companies->tidy_company( $obj ); + break; + case ZBS_TYPE_QUOTE: + return $this->quotes->tidy_quote( $obj ); + break; + case ZBS_TYPE_INVOICE: + return $this->invoices->tidy_invoice( $obj ); + break; + case ZBS_TYPE_TRANSACTION: + return $this->transactions->tidy_transaction( $obj ); + break; + case ZBS_TYPE_TASK: + return $this->events->tidy_event( $obj ); + break; + case ZBS_TYPE_FORM: + return $this->forms->tidy_form( $obj ); + break; + case ZBS_TYPE_LOG: + return $this->logs->tidy_log( $obj ); + break; + case ZBS_TYPE_SEGMENT: + return $this->segments->tidy_segment( $obj ); + break; + case ZBS_TYPE_LINEITEM: + return $this->lineitems->tidy_lineitem( $obj ); + break; + case ZBS_TYPE_TASK_REMINDER: + return $this->eventreminders->tidy_eventreminder( $obj ); + break; + case ZBS_TYPE_QUOTETEMPLATE: + return $this->quotetemplates->tidy_quotetemplate( $obj ); + break; - // appends a space, if req. (lazy helper for amongst queries) - public function space($str='',$pre=false){ + } - if (!empty($str)) - if ($pre) - return ' '.$str; - else - return $str.' '; + return false; + } - return $str; + // guesses at a tidy... lazy, remove these if hit walls + public function lazyTidyGeneric( $obj = false ) { - } + $res = false; - // appends a space and 'AND', if req. (lazy helper for amongst queries) - public function spaceAnd($str=''){ + foreach ( $obj as $propKey => $prop ) { - if (!empty($str)) return $str.' AND '; + if ( ! is_array( $res ) ) { + $res = array(); + } - return $str; + if ( $propKey != 'ID' && strpos( $propKey, '_' ) > 0 ) { - } + // zbs_owner -> owner + $newKey = substr( $propKey, strpos( $propKey, '_' ) + 1 ); - // appends a space and 'Where', if req. (lazy helper for amongst queries) - public function spaceWhere($str=''){ + $res[ $newKey ] = $this->stripSlashes( $prop ); - $trimmedStr = trim($str); - if (!empty($trimmedStr)) return ' WHERE '.$trimmedStr; + } else { + $res['id'] = $prop; + } + } - return $str; + return $res; + } - } + // appends a space, if req. (lazy helper for amongst queries) + public function space( $str = '', $pre = false ) { - // returns delimiter, if str != epty - // used to be zeroBS_delimiterIf pre dal1 - public function delimiterIf($delimiter,$ifStr=''){ + if ( ! empty( $str ) ) { + if ( $pre ) { + return ' ' . $str; + } else { + return $str . ' '; + } + } - if (!empty($ifStr)) return $delimiter; + return $str; + } - return ''; - } + // appends a space and 'AND', if req. (lazy helper for amongst queries) + public function spaceAnd( $str = '' ) { - // internal middle man for zeroBSCRM_stripSlashes where ALWAYS returns - public function stripSlashes($obj=false){ + if ( ! empty( $str ) ) { + return $str . ' AND '; + } - return zeroBSCRM_stripSlashes($obj,true); + return $str; + } - } + // appends a space and 'Where', if req. (lazy helper for amongst queries) + public function spaceWhere( $str = '' ) { - // if it thinks str is json, it'll decode + return obj, otherwise returns str - // this only works with arr/obj - // Note that `[]` doesn't hydrate into array with this - public function decodeIfJSON($str=''){ + $trimmedStr = trim( $str ); + if ( ! empty( $trimmedStr ) ) { + return ' WHERE ' . $trimmedStr; + } - if (zeroBSCRM_isJson($str)) return json_decode($str,true); // true req. https://stackoverflow.com/questions/22878219/json-encode-turns-array-into-an-object + return $str; + } - return $str; - } + // returns delimiter, if str != epty + // used to be zeroBS_delimiterIf pre dal1 + public function delimiterIf( $delimiter, $ifStr = '' ) { + if ( ! empty( $ifStr ) ) { + return $delimiter; + } - /* - * Builds Custom Fields Order by Str - * .. ultimately returns $sortByField unless numeric, if so casts the custom field (varchar) - * .. into an INT/DECIMAL in MySQL for the search - */ - public function build_custom_field_order_by_str( $sortByField='', $customField=array() ){ + return ''; + } - // check if this custom field requires any special casting in it's sort string - - // where the CF is a numeric field, we'll need to also use CAST(* AS SIGNED) - if ( $customField[0] == 'numberint' ){ + // internal middle man for zeroBSCRM_stripSlashes where ALWAYS returns + public function stripSlashes( $obj = false ) { - $sortByField = 'CAST('.$sortByField.' AS SIGNED)'; + return zeroBSCRM_stripSlashes( $obj, true ); + } - } + // if it thinks str is json, it'll decode + return obj, otherwise returns str + // this only works with arr/obj + // Note that `[]` doesn't hydrate into array with this + public function decodeIfJSON( $str = '' ) { - // where the CF is a decimal field, we'll need to use CAST(* AS DECIMAL) - if ( $customField[0] == 'numberfloat' ){ + if ( zeroBSCRM_isJson( $str ) ) { + return json_decode( $str, true ); // true req. https://stackoverflow.com/questions/22878219/json-encode-turns-array-into-an-object + } + return $str; + } - $sortByField = 'CAST('.$sortByField.' AS DECIMAL(18,2))'; - } + /* + * Builds Custom Fields Order by Str + * .. ultimately returns $sortByField unless numeric, if so casts the custom field (varchar) + * .. into an INT/DECIMAL in MySQL for the search + */ + public function build_custom_field_order_by_str( $sortByField = '', $customField = array() ) { - return $sortByField; + // check if this custom field requires any special casting in it's sort string - } + // where the CF is a numeric field, we'll need to also use CAST(* AS SIGNED) + if ( $customField[0] == 'numberint' ) { - /* - * Build's an escaped imploded, DB safe CSV - * e.g. "'a','b','c'" as used in SELECT * FROM x WHERE y in ('a','b','c') - */ - public function build_csv($array=array()){ + $sortByField = 'CAST(' . $sortByField . ' AS SIGNED)'; - // only arrays - if (!is_array($array)) return ''; + } - // Generate escaped csv, e.g. 'Call','Email' - $array = array_map(function($v) { - return "'" . esc_sql($v) . "'"; - }, $array); + // where the CF is a decimal field, we'll need to use CAST(* AS DECIMAL) + if ( $customField[0] == 'numberfloat' ) { - // return - return implode(',', $array); + $sortByField = 'CAST(' . $sortByField . ' AS DECIMAL(18,2))'; + } - } + return $sortByField; + } + /* + * Build's an escaped imploded, DB safe CSV + * e.g. "'a','b','c'" as used in SELECT * FROM x WHERE y in ('a','b','c') + */ + public function build_csv( $array = array() ) { - // takes wherestr + additionalwhere and outputs legit SQL - // GENERIC helper for all queries :) - public function buildWhereStr($whereStr='',$additionalWhere=''){ + // only arrays + if ( ! is_array( $array ) ) { + return ''; + } - //echo 'W:'.$whereStr.'
AW:'.$additionalWhere.'!!

'; - - #} Build - $where = trim($whereStr); + // Generate escaped csv, e.g. 'Call','Email' + $array = array_map( + function ( $v ) { + return "'" . esc_sql( $v ) . "'"; + }, + $array + ); - #} Any additional - if (!empty($additionalWhere)){ - if (!empty($where)) - $where = $this->spaceAnd($where); - else - $where = 'WHERE '; - $where .= $additionalWhere; - } + // return + return implode( ',', $array ); + } - return $this->space($where,true); - } + // takes wherestr + additionalwhere and outputs legit SQL + // GENERIC helper for all queries :) + public function buildWhereStr( $whereStr = '', $additionalWhere = '' ) { - // add where's to SQL - // + - // feed in params - // GENERIC helper for all queries :) - public function buildWheres($wheres=array(),$whereStr='',$params=array(),$andOr='AND',$includeInitialWHERE=true){ + // echo 'W:'.$whereStr.'
AW:'.$additionalWhere.'!!

'; - $ret = array('where'=>$whereStr,'params'=>$params); if ($andOr != 'AND' && $andOr != 'OR') $andOr = 'AND'; + #} Build + $where = trim( $whereStr ); - // clear empty direct - if (isset($wheres['direct']) && is_array($wheres['direct']) && count($wheres['direct']) == 0) unset($wheres['direct']); + #} Any additional + if ( ! empty( $additionalWhere ) ) { + if ( ! empty( $where ) ) { + $where = $this->spaceAnd( $where ); + } else { + $where = 'WHERE '; + } + $where .= $additionalWhere; + } - if (is_array($wheres) && count($wheres) > 0) foreach ($wheres as $key => $whereArr) { + return $this->space( $where, true ); + } - if (empty($ret['where']) && $includeInitialWHERE) $ret['where'].= ' WHERE '; + // add where's to SQL + // + + // feed in params + // GENERIC helper for all queries :) + public function buildWheres( $wheres = array(), $whereStr = '', $params = array(), $andOr = 'AND', $includeInitialWHERE = true ) { - // Where's are passed 2 ways, "direct": - // array(SQL,array(params)) - if ($key == 'direct'){ + $ret = array( + 'where' => $whereStr, + 'params' => $params, + ); + if ( $andOr != 'AND' && $andOr != 'OR' ) { + $andOr = 'AND'; + } - // several under 1 direct - foreach ($whereArr as $directWhere){ + // clear empty direct + if ( isset( $wheres['direct'] ) && is_array( $wheres['direct'] ) && count( $wheres['direct'] ) == 0 ) { + unset( $wheres['direct'] ); + } - if (isset($directWhere[0]) && isset($directWhere[1])){ + if ( is_array( $wheres ) && count( $wheres ) > 0 ) { + foreach ( $wheres as $key => $whereArr ) { - // multi-direct ANDor - if (!empty($ret['where']) && $ret['where'] != ' WHERE '){ - $ret['where'] .= ' '.$andOr.' '; - } - - // ++ query - $ret['where'] .= $directWhere[0]; + if ( empty( $ret['where'] ) && $includeInitialWHERE ) { + $ret['where'] .= ' WHERE '; + } - // ++ params (any number, if set) - if (is_array($directWhere[1])) - foreach ($directWhere[1] as $x) $ret['params'][] = $x; - else - $ret['params'][] = $directWhere[1]; - } + // Where's are passed 2 ways, "direct": + // array(SQL,array(params)) + if ( $key == 'direct' ) { - } + // several under 1 direct + foreach ( $whereArr as $directWhere ) { - } else { + if ( isset( $directWhere[0] ) && isset( $directWhere[1] ) ) { - if (!empty($ret['where']) && $ret['where'] != ' WHERE '){ - $ret['where'] .= ' '.$andOr.' '; - } + // multi-direct ANDor + if ( ! empty( $ret['where'] ) && $ret['where'] != ' WHERE ' ) { + $ret['where'] .= ' ' . $andOr . ' '; + } - // Other way: - // irrelevantKEY => array(fieldname,operator,comparisonval,array(params)) - // e.g. array('ID','=','%d',array(123)) - // e.g. array('ID','IN','(SUBSELECT)',array(123)) + // ++ query + $ret['where'] .= $directWhere[0]; - // build where (e.g. "X = Y" or "Z IN (1,2,3)") - $ret['where'] .= $whereArr[0]. ' '.$whereArr[1].' '.$whereArr[2]; + // ++ params (any number, if set) + if ( is_array( $directWhere[1] ) ) { + foreach ( $directWhere[1] as $x ) { + $ret['params'][] = $x; + } + } else { + $ret['params'][] = $directWhere[1]; + } + } + } + } else { - // ++ params (any number, if set) - if (isset($whereArr[3])) { - if (is_array($whereArr[3])) - foreach ($whereArr[3] as $x) $ret['params'][] = $x; - else - $ret['params'][] = $whereArr[3]; - } + if ( ! empty( $ret['where'] ) && $ret['where'] != ' WHERE ' ) { + $ret['where'] .= ' ' . $andOr . ' '; + } - /* legacy + // Other way: + // irrelevantKEY => array(fieldname,operator,comparisonval,array(params)) + // e.g. array('ID','=','%d',array(123)) + // e.g. array('ID','IN','(SUBSELECT)',array(123)) + + // build where (e.g. "X = Y" or "Z IN (1,2,3)") + $ret['where'] .= $whereArr[0] . ' ' . $whereArr[1] . ' ' . $whereArr[2]; + + // ++ params (any number, if set) + if ( isset( $whereArr[3] ) ) { + if ( is_array( $whereArr[3] ) ) { + foreach ( $whereArr[3] as $x ) { + $ret['params'][] = $x; + } + } else { + $ret['params'][] = $whereArr[3]; + } + } - // add in - NOTE: this is TRUSTING key + whereArr[0] - $ret['where'] .= $key.' '.$whereArr[0].' '.$whereArr[2]; + /* + legacy - // feed in params - $ret['params'][] = $whereArr[1]; - */ + // add in - NOTE: this is TRUSTING key + whereArr[0] + $ret['where'] .= $key.' '.$whereArr[0].' '.$whereArr[2]; - } + // feed in params + $ret['params'][] = $whereArr[1]; + */ - } + } + } + } - return $ret; - } + return $ret; + } /** * Builds JOIN SQL for DAL queries. @@ -7520,88 +8554,94 @@ public function build_joins( $joins = array(), $match_all = true ) { return array( $join_sql, $join_params ); } - // takes sortby field + order and returns str if not empty :) - // Note: Is trusting legitimacy of $sortByField as parametised in wp db doesn't seem to work - // can also now pass array (multi-sort) - // e.g. $sortByField = 'zbsc_fname' OR $sortByField = array('zbsc_fname'=>'ASC','zbsc_lname' => 'DESC'); - public function buildSort($sortByField='',$sortOrder='ASC'){ + // takes sortby field + order and returns str if not empty :) + // Note: Is trusting legitimacy of $sortByField as parametised in wp db doesn't seem to work + // can also now pass array (multi-sort) + // e.g. $sortByField = 'zbsc_fname' OR $sortByField = array('zbsc_fname'=>'ASC','zbsc_lname' => 'DESC'); + public function buildSort( $sortByField = '', $sortOrder = 'ASC' ) { - #} Sort by - if (!is_array($sortByField) && !empty($sortByField)){ + #} Sort by + if ( ! is_array( $sortByField ) && ! empty( $sortByField ) ) { - $sortOrder = strtoupper($sortOrder); + $sortOrder = strtoupper( $sortOrder ); - if (!in_array($sortOrder, array('DESC','ASC'))) $sortOrder = 'DESC'; - return ' ORDER BY '.$sortByField.' '.$sortOrder; - - } else if (is_array($sortByField)){ - - $orderByStr = ''; - foreach ($sortByField as $field => $order){ - - if (!empty($orderByStr)) $orderByStr .= ', '; - $orderByStr .= $field.' '.strtoupper($order); + if ( ! in_array( $sortOrder, array( 'DESC', 'ASC' ) ) ) { + $sortOrder = 'DESC'; + } + return ' ORDER BY ' . $sortByField . ' ' . $sortOrder; - } + } elseif ( is_array( $sortByField ) ) { - if (!empty($orderByStr)) return ' ORDER BY '.$orderByStr; + $orderByStr = ''; + foreach ( $sortByField as $field => $order ) { - } + if ( ! empty( $orderByStr ) ) { + $orderByStr .= ', '; + } + $orderByStr .= $field . ' ' . strtoupper( $order ); - return ''; - } + } + if ( ! empty( $orderByStr ) ) { + return ' ORDER BY ' . $orderByStr; + } + } - // takes $page and $perPage and adds limit str if req. - public function buildPaging($page=-1,$perPage=-1){ + return ''; + } - #} Pagination - if ($page == -1 && $perPage == -1){ + // takes $page and $perPage and adds limit str if req. + public function buildPaging( $page = -1, $perPage = -1 ) { - // NO LIMITS :o + #} Pagination + if ( $page == -1 && $perPage == -1 ) { - } else { + // NO LIMITS :o - $perPage = (int)$perPage; + } else { - // Because SQL USING zero indexed page numbers, we remove -1 here - // ... DO NOT change this without seeing usage of the function (e.g. list view) - which'll break - $page = (int)$page-1; - if ($page < 0) $page = 0; + $perPage = (int) $perPage; - // page needs multiplying :) - if ($page > 0) $page = $page * $perPage; + // Because SQL USING zero indexed page numbers, we remove -1 here + // ... DO NOT change this without seeing usage of the function (e.g. list view) - which'll break + $page = (int) $page - 1; + if ( $page < 0 ) { + $page = 0; + } - // check params realistic - // todo, for now, brute pass - return ' LIMIT '.(int)$page.','.(int)$perPage; + // page needs multiplying :) + if ( $page > 0 ) { + $page = $page * $perPage; + } - } + // check params realistic + // todo, for now, brute pass + return ' LIMIT ' . (int) $page . ',' . (int) $perPage; - return ''; - } + } + return ''; + } - // builds WHERE query for meta key / val pairs. - // e.g. Get customers in Company id 9: - // ... contacts where their ID is in post_id WHERE meta_key = zbs_company and meta_value = 9 - // infill for half-migrated stuff - public function buildWPMetaQueryWhere($metaKey=-1,$metaVal=-1){ + // builds WHERE query for meta key / val pairs. + // e.g. Get customers in Company id 9: + // ... contacts where their ID is in post_id WHERE meta_key = zbs_company and meta_value = 9 + // infill for half-migrated stuff + public function buildWPMetaQueryWhere( $metaKey = -1, $metaVal = -1 ) { - if (!empty($metaKey) && !empty($metaVal)){ + if ( ! empty( $metaKey ) && ! empty( $metaVal ) ) { - global $wpdb; - return array( - - 'sql' => 'ID IN (SELECT DISTINCT post_id FROM '.$wpdb->prefix.'postmeta WHERE meta_key = %s AND meta_value = %d)', - 'params' => array($metaKey,$metaVal) - ); + global $wpdb; + return array( - } + 'sql' => 'ID IN (SELECT DISTINCT post_id FROM ' . $wpdb->prefix . 'postmeta WHERE meta_key = %s AND meta_value = %d)', + 'params' => array( $metaKey, $metaVal ), + ); - return false; + } - } + return false; + } /** * Generates GROUP_CONCAT SQL compatible with both SQLite and MySQL @@ -7620,288 +8660,294 @@ public function build_group_concat( $field, $separator ) { } } - // this returns %s etc. for common field names, will default to %s unless somt obv a date - public function getTypeStr($fieldKey=''){ - - if ($fieldKey == 'zbs_site' || $fieldKey == 'zbs_team' || $fieldKey == 'zbs_owner') return '%d'; - - if (strpos($fieldKey, '_created') > 0) return '%d'; - if (strpos($fieldKey, '_lastupdated') > 0) return '%d'; - if (strpos($fieldKey, '_lastcontacted') > 0) return '%d'; - if (strpos($fieldKey, '_id') > 0) return '%d'; - if (strpos($fieldKey, '_ID') > 0) return '%d'; - if ($fieldKey == 'id' || $fieldKey == 'ID') return '%d'; - - return '%s'; - - } - - /* - * Converts verbs such as 'equal' to '=' - * Note: these are relatively idiosyncratic as were part of segmentation layer but got generalised here - */ - public function comparison_to_sql_symbol( $comparison_verb ){ - - switch ( $comparison_verb ){ - - case 'equal': - case 'equals': - return '='; - break; - case 'notequal': - return '<>'; - break; - case 'larger': - return '>'; - break; - case 'largerequal': - return '>='; - break; - case 'less': - return '<'; - break; - case 'lessequal': - return '<='; - break; - case 'floatrange': - // this is somewhat like hotglue, e.g. `WHERE column_a [BETWEEN %s AND ] %s` - return 'BETWEEN %s AND '; - break; - case 'intrange': - // this is somewhat like hotglue, e.g. `WHERE column_a [BETWEEN %d AND ] %d` - return 'BETWEEN %d AND '; - break; - - } - - return false; - - } - - public function prepare($sql='',$params=array()){ - - global $wpdb; - - // empty arrays causes issues in wpdb prepare - if (is_array($params) && count($params) <= 0) return $sql; + // this returns %s etc. for common field names, will default to %s unless somt obv a date + public function getTypeStr( $fieldKey = '' ) { - // normal return - return $wpdb->prepare($sql,$params); - - } - - // not yet used - public function catchSQLError($errObj=-1){ - - - // log? - - return false; - - } - - /* - * Retrieves a key-value pair from centralised global - * - * @param string $key - * - */ - public function get_cache_var( $key ){ - - if ( isset( $this->cache[ $key ] ) ){ - - return $this->cache[ $key ]; - - } - - return false; - - } + if ( $fieldKey == 'zbs_site' || $fieldKey == 'zbs_team' || $fieldKey == 'zbs_owner' ) { + return '%d'; + } - /* - * Stores a key-value pair in centralised global - * This is designed to allow basic caching at a DAL level without spawning multiple globals - * - * @param string $key - * @param mixed $value - * - */ - public function update_cache_var( $key, $value ){ + if ( strpos( $fieldKey, '_created' ) > 0 ) { + return '%d'; + } + if ( strpos( $fieldKey, '_lastupdated' ) > 0 ) { + return '%d'; + } + if ( strpos( $fieldKey, '_lastcontacted' ) > 0 ) { + return '%d'; + } + if ( strpos( $fieldKey, '_id' ) > 0 ) { + return '%d'; + } + if ( strpos( $fieldKey, '_ID' ) > 0 ) { + return '%d'; + } + if ( $fieldKey == 'id' || $fieldKey == 'ID' ) { + return '%d'; + } - // simplistic - $this->cache[ $key ] = $value; + return '%s'; + } - } + /* + * Converts verbs such as 'equal' to '=' + * Note: these are relatively idiosyncratic as were part of segmentation layer but got generalised here + */ + public function comparison_to_sql_symbol( $comparison_verb ) { + switch ( $comparison_verb ) { + case 'equal': + case 'equals': + return '='; + break; + case 'notequal': + return '<>'; + break; + case 'larger': + return '>'; + break; + case 'largerequal': + return '>='; + break; + case 'less': + return '<'; + break; + case 'lessequal': + return '<='; + break; + case 'floatrange': + // this is somewhat like hotglue, e.g. `WHERE column_a [BETWEEN %s AND ] %s` + return 'BETWEEN %s AND '; + break; + case 'intrange': + // this is somewhat like hotglue, e.g. `WHERE column_a [BETWEEN %d AND ] %d` + return 'BETWEEN %d AND '; + break; -/* ====================================================== - / To be sorted helpers - ====================================================== */ + } + return false; + } + public function prepare( $sql = '', $params = array() ) { + global $wpdb; + // empty arrays causes issues in wpdb prepare + if ( is_array( $params ) && count( $params ) <= 0 ) { + return $sql; + } + // normal return + return $wpdb->prepare( $sql, $params ); + } + // not yet used + public function catchSQLError( $errObj = -1 ) { + // log? + return false; + } + /* + * Retrieves a key-value pair from centralised global + * + * @param string $key + * + */ + public function get_cache_var( $key ) { -/* ====================================================== - Middle Man funcs (until DAL3.1) - ====================================================== */ + if ( isset( $this->cache[ $key ] ) ) { - // TEMP LOGGING to BACKTRACE LEGACY CALLS: - /* CREATE TABLE `templogs` ( - `ID` int(32) NOT NULL AUTO_INCREMENT PRIMARY KEY, - `funcname` varchar(500) NOT NULL, - `filename` varchar(500) NOT NULL, - `notes` longtext NOT NULL, - `time` int(14) NOT NULL -) ENGINE='InnoDB' COLLATE 'utf8_general_ci'; */ + return $this->cache[ $key ]; + } - // temporary function used in v3.0 prep to weed out bad/old reference use - // logs to table 'templogs' if table exists - // left in until 3.1 - see #gh-146 - private function v3templogBacktrace($funcName='',$caller=false,$backtrace=false){ + return false; + } - global $ZBSCRM_t,$wpdb; - - $tableExist = $wpdb->get_results("SHOW TABLES LIKE 'templogs'"); - if (count($tableExist) >= 1){ - - if ($wpdb->insert( - 'templogs', - array( - // fields - 'funcname' => $funcName, - 'filename' => $caller['file'].':'.$caller['line'], - 'notes' => print_r($backtrace,1),//, - 'time' => time() - ), - array( - '%s', - '%s', - '%s', - '%d' - ) ) <= 0) exit('ERROR: Failed to log backtrace error ('.$funcName.')!
'.print_r(array($backtrace,$caller,$funcName),1).'
'); - - } + /* + * Stores a key-value pair in centralised global + * This is designed to allow basic caching at a DAL level without spawning multiple globals + * + * @param string $key + * @param mixed $value + * + */ + public function update_cache_var( $key, $value ) { + + // simplistic + $this->cache[ $key ] = $value; + } - return true; + /* + ====================================================== + / To be sorted helpers + ====================================================== */ + + /* + ====================================================== + Middle Man funcs (until DAL3.1) + ====================================================== */ + + // TEMP LOGGING to BACKTRACE LEGACY CALLS: + /* + CREATE TABLE `templogs` ( + `ID` int(32) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `funcname` varchar(500) NOT NULL, + `filename` varchar(500) NOT NULL, + `notes` longtext NOT NULL, + `time` int(14) NOT NULL + ) ENGINE='InnoDB' COLLATE 'utf8_general_ci'; */ + + // temporary function used in v3.0 prep to weed out bad/old reference use + // logs to table 'templogs' if table exists + // left in until 3.1 - see #gh-146 + private function v3templogBacktrace( $funcName = '', $caller = false, $backtrace = false ) { + + global $ZBSCRM_t, $wpdb; + + $tableExist = $wpdb->get_results( "SHOW TABLES LIKE 'templogs'" ); + if ( count( $tableExist ) >= 1 ) { + + if ( $wpdb->insert( + 'templogs', + array( + // fields + 'funcname' => $funcName, + 'filename' => $caller['file'] . ':' . $caller['line'], + 'notes' => print_r( $backtrace, 1 ), // , + 'time' => time(), + ), + array( + '%s', + '%s', + '%s', + '%d', + ) + ) <= 0 ) { + exit( 'ERROR: Failed to log backtrace error (' . $funcName . ')!
' . print_r( array( $backtrace, $caller, $funcName ), 1 ) . '
' ); + } + } - } + return true; + } /** * Counts below are as of 19 November 2024. */ /* Stripe Sync: 1 */ -public function getContact(...$args){ + public function getContact( ...$args ) { - // hard-typed - $funcName = 'getContact'; - - // retrieve backtrace - $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); - $caller = array_shift($backtrace); + // hard-typed + $funcName = 'getContact'; - // log to db, if logging - $this->v3templogBacktrace($funcName,$caller,$backtrace); + // retrieve backtrace + $backtrace = debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, 1 ); + $caller = array_shift( $backtrace ); - // return, if available - if (method_exists($this->contacts, $funcName)) return call_user_func_array(array($this->contacts,$funcName),func_get_args()); + // log to db, if logging + $this->v3templogBacktrace( $funcName, $caller, $backtrace ); - // ultimate fallback - return false; + // return, if available + if ( method_exists( $this->contacts, $funcName ) ) { + return call_user_func_array( array( $this->contacts, $funcName ), func_get_args() ); + } -} + // ultimate fallback + return false; + } /* Automations: 1 */ -public function getContacts(...$args){ + public function getContacts( ...$args ) { - // hard-typed - $funcName = 'getContacts'; - - // retrieve backtrace - $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); - $caller = array_shift($backtrace); + // hard-typed + $funcName = 'getContacts'; - // log to db, if logging - $this->v3templogBacktrace($funcName,$caller,$backtrace); + // retrieve backtrace + $backtrace = debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, 1 ); + $caller = array_shift( $backtrace ); - // return, if available - if (method_exists($this->contacts, $funcName)) return call_user_func_array(array($this->contacts,$funcName),func_get_args()); + // log to db, if logging + $this->v3templogBacktrace( $funcName, $caller, $backtrace ); - // ultimate fallback - return false; + // return, if available + if ( method_exists( $this->contacts, $funcName ) ) { + return call_user_func_array( array( $this->contacts, $funcName ), func_get_args() ); + } -} + // ultimate fallback + return false; + } /* Stripe Sync: 1, Awesome Support: 1 */ -public function addUpdateContact(...$args){ + public function addUpdateContact( ...$args ) { - // hard-typed - $funcName = 'addUpdateContact'; - - // retrieve backtrace - $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); - $caller = array_shift($backtrace); + // hard-typed + $funcName = 'addUpdateContact'; - // log to db, if logging - $this->v3templogBacktrace($funcName,$caller,$backtrace); + // retrieve backtrace + $backtrace = debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, 1 ); + $caller = array_shift( $backtrace ); - // return, if available - if (method_exists($this->contacts, $funcName)) return call_user_func_array(array($this->contacts,$funcName),func_get_args()); + // log to db, if logging + $this->v3templogBacktrace( $funcName, $caller, $backtrace ); - // ultimate fallback - return false; + // return, if available + if ( method_exists( $this->contacts, $funcName ) ) { + return call_user_func_array( array( $this->contacts, $funcName ), func_get_args() ); + } -} + // ultimate fallback + return false; + } /* Automations: 1, Livestorm: 1 */ // phpcs:ignore Squiz.PHP.CommentedOutCode.Found -public function addUpdateContactTags(...$args){ + public function addUpdateContactTags( ...$args ) { - // hard-typed - $funcName = 'addUpdateContactTags'; - - // retrieve backtrace - $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); - $caller = array_shift($backtrace); + // hard-typed + $funcName = 'addUpdateContactTags'; - // log to db, if logging - $this->v3templogBacktrace($funcName,$caller,$backtrace); + // retrieve backtrace + $backtrace = debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, 1 ); + $caller = array_shift( $backtrace ); - // return, if available - if (method_exists($this->contacts, $funcName)) return call_user_func_array(array($this->contacts,$funcName),func_get_args()); + // log to db, if logging + $this->v3templogBacktrace( $funcName, $caller, $backtrace ); - // ultimate fallback - return false; + // return, if available + if ( method_exists( $this->contacts, $funcName ) ) { + return call_user_func_array( array( $this->contacts, $funcName ), func_get_args() ); + } -} + // ultimate fallback + return false; + } /* Automations: 1 */ -public function deleteContact(...$args){ + public function deleteContact( ...$args ) { - // hard-typed - $funcName = 'deleteContact'; - - // retrieve backtrace - $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1); - $caller = array_shift($backtrace); + // hard-typed + $funcName = 'deleteContact'; - // log to db, if logging - $this->v3templogBacktrace($funcName,$caller,$backtrace); + // retrieve backtrace + $backtrace = debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, 1 ); + $caller = array_shift( $backtrace ); - // return, if available - if (method_exists($this->contacts, $funcName)) return call_user_func_array(array($this->contacts,$funcName),func_get_args()); + // log to db, if logging + $this->v3templogBacktrace( $funcName, $caller, $backtrace ); - // ultimate fallback - return false; + // return, if available + if ( method_exists( $this->contacts, $funcName ) ) { + return call_user_func_array( array( $this->contacts, $funcName ), func_get_args() ); + } -} + // ultimate fallback + return false; + } /* Advanced Segments: 4 */ public function segmentBuildDirectOrClause( ...$args ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid,VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable,Squiz.Commenting.FunctionComment.WrongStyle @@ -7923,9 +8969,10 @@ public function segmentBuildDirectOrClause( ...$args ) { // phpcs:ignore WordPre return false; } -/* ====================================================== - / Middle Man funcs (until DAL3.0) - ====================================================== */ + /* + ====================================================== + / Middle Man funcs (until DAL3.0) + ====================================================== */ } // / DAL class // Initialize the static mitigation cache. diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DashboardBoxes.php b/projects/plugins/crm/includes/ZeroBSCRM.DashboardBoxes.php index adf745123b35..2cff3ab156c8 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DashboardBoxes.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DashboardBoxes.php @@ -1,5 +1,6 @@ -DAL->contacts->getContacts( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DataIOValidation.php b/projects/plugins/crm/includes/ZeroBSCRM.DataIOValidation.php index 09b4c49fb98c..1333b06691c8 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DataIOValidation.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DataIOValidation.php @@ -1,5 +1,6 @@ - - function zeroBSCRM_stripExceptLineBreaks($string=''){ - - // simplistic switchout. can surely be done more elegantly - $brs = array('
','
','
','
','
','
'); - $str = str_replace($brs,'###BR###',$string); - $str = wp_strip_all_tags($str,1); - $str = str_replace('###BR###','
',$str); - - return $str; - } - - /* - * sanitize_text_field, but allows whitespace through :roll-eyes: - * https://developer.wordpress.org/reference/functions/sanitize_text_field/ - */ - function jpcrm_sanitize_text_field_allow_whitespace( $string = '' ){ - - $string = str_replace( ' ', '**WHITESPACE**', $string ); - $string = sanitize_text_field( $string ); - return str_replace( '**WHITESPACE**', ' ', $string ); - - } - - // lol https://stackoverflow.com/questions/6063184/how-to-strip-all-characters-except-for-alphanumeric-and-underscore-and-dash - function zeroBSCRM_strings_stripNonAlphaNumeric_dash($str=''){ - return preg_replace("/[^a-z0-9_\-\s]+/i", "", $str); - } + // encode emoji's - https://core.trac.wordpress.org/ticket/43087 + return wp_encode_emoji( $string ); +} - // https://stackoverflow.com/questions/33993461/php-remove-all-non-numeric-characters-from-a-string - function zeroBSCRM_strings_stripNonNumeric($str=''){ - return preg_replace("/[^0-9]/", "", $str); - } + // strips all except
+function zeroBSCRM_stripExceptLineBreaks( $string = '' ) { -/* ====================================================== - / Data Processing Functions - ====================================================== */ + // simplistic switchout. can surely be done more elegantly + $brs = array( '
', '
', '
', '
', '
', '
' ); + $str = str_replace( $brs, '###BR###', $string ); + $str = wp_strip_all_tags( $str, 1 ); + $str = str_replace( '###BR###', '
', $str ); + return $str; +} + /* + * sanitize_text_field, but allows whitespace through :roll-eyes: + * https://developer.wordpress.org/reference/functions/sanitize_text_field/ + */ +function jpcrm_sanitize_text_field_allow_whitespace( $string = '' ) { + $string = str_replace( ' ', '**WHITESPACE**', $string ); + $string = sanitize_text_field( $string ); + return str_replace( '**WHITESPACE**', ' ', $string ); +} -/* ====================================================== - Data Validation Functions - ====================================================== */ + // lol https://stackoverflow.com/questions/6063184/how-to-strip-all-characters-except-for-alphanumeric-and-underscore-and-dash +function zeroBSCRM_strings_stripNonAlphaNumeric_dash( $str = '' ) { + return preg_replace( '/[^a-z0-9_\-\s]+/i', '', $str ); +} - /* - * Taking a variable, this function checks if it could be an int - * (returns true if is an int or a string which could be an int) - .. with a little help from my friends: https://stackoverflow.com/questions/2012187/how-to-check-that-a-string-is-an-int-but-not-a-double-etc - */ - function jpcrm_is_int( $var = false ){ + // https://stackoverflow.com/questions/33993461/php-remove-all-non-numeric-characters-from-a-string +function zeroBSCRM_strings_stripNonNumeric( $str = '' ) { + return preg_replace( '/[^0-9]/', '', $str ); +} - // straight check - if ( is_int($var) ) return true; +/* +====================================================== + / Data Processing Functions + ====================================================== */ + +/* +====================================================== + Data Validation Functions + ====================================================== */ + + /* + * Taking a variable, this function checks if it could be an int + * (returns true if is an int or a string which could be an int) + .. with a little help from my friends: https://stackoverflow.com/questions/2012187/how-to-check-that-a-string-is-an-int-but-not-a-double-etc + */ +function jpcrm_is_int( $var = false ) { + + // straight check + if ( is_int( $var ) ) { + return true; + } - // string check - if ( is_string($var) ){ + // string check + if ( is_string( $var ) ) { - // catch negative + // catch negative if ( str_starts_with( $var, '-' ) ) { - // use ctype where available - if ( function_exists('ctype_digit') ){ - return ctype_digit( substr($var, 1) ); - } else { - return is_numeric( $var ); - } + // use ctype where available + if ( function_exists( 'ctype_digit' ) ) { + return ctype_digit( substr( $var, 1 ) ); + } else { + return is_numeric( $var ); + } } - // use ctype_digit where available to check the string only contains digits - if ( function_exists('ctype_digit') ){ - return ctype_digit( $var ); - } else { - return is_numeric( $var ); - } - - } - - return false; + // use ctype_digit where available to check the string only contains digits + if ( function_exists( 'ctype_digit' ) ) { + return ctype_digit( $var ); + } else { + return is_numeric( $var ); + } + } - } + return false; +} /** * Checks if a given string is a URL @@ -169,29 +165,33 @@ function jpcrm_url_with_scheme( $s, $scheme = 'https' ) { } #} Checks an email addr - function zeroBSCRM_validateEmail($emailAddr){ - - if (filter_var($emailAddr, FILTER_VALIDATE_EMAIL)) return true; - - return false; +function zeroBSCRM_validateEmail( $emailAddr ) { + if ( filter_var( $emailAddr, FILTER_VALIDATE_EMAIL ) ) { + return true; } - function zeroBSCRM_dataIO_postedArrayOfInts($array=false){ + return false; +} + +function zeroBSCRM_dataIO_postedArrayOfInts( $array = false ) { - $ret = array(); if (is_array($array)) $ret = $array; + $ret = array(); + if ( is_array( $array ) ) { + $ret = $array; + } - // sanitize - $ret = array_map( 'sanitize_text_field', $ret ); - $ret = array_map( 'intval', $ret ); + // sanitize + $ret = array_map( 'sanitize_text_field', $ret ); + $ret = array_map( 'intval', $ret ); - return $ret; - } + return $ret; +} - /* - * Checks file path doesn't use unsafe/undesirable protocols - */ - function jpcrm_dataIO_file_path_seems_unsafe( $file_path_string ){ + /* + * Checks file path doesn't use unsafe/undesirable protocols + */ +function jpcrm_dataIO_file_path_seems_unsafe( $file_path_string ) { // this one is important enough to be hard typed here #gh-2501 if ( str_contains( $file_path_string, 'phar' ) ) { @@ -224,77 +224,82 @@ function jpcrm_url_appears_to_match_site( $url_string, $site_path = '' ) { return false; } -/* ====================================================== - / Data Validation Functions - ====================================================== */ +/* +====================================================== + / Data Validation Functions + ====================================================== */ +/* +====================================================== + Data Validation Functions: Segments + ====================================================== */ -/* ====================================================== - Data Validation Functions: Segments - ====================================================== */ - -// filters out segment conditions (From anything passed) which are not 'safe' +// filters out segment conditions (From anything passed) which are not 'safe' // e.g. on our zeroBSCRM_segments_availableConditions() list // ACCEPTS a POST arr // $processCharacters dictates whether or not to pass strings through zeroBSCRM_textProcess // ... only do so pre-save, not pre "preview" because this html encodes special chars. - // note $processCharacters now legacy/defunct. -function zeroBSCRM_segments_filterConditions($conditions=array(),$processCharacters=true){ + // note $processCharacters now legacy/defunct. +function zeroBSCRM_segments_filterConditions( $conditions = array(), $processCharacters = true ) { - if (is_array($conditions) && count($conditions) > 0){ + if ( is_array( $conditions ) && count( $conditions ) > 0 ) { - $approvedConditions = array(); + $approvedConditions = array(); - $availableConditions = zeroBSCRM_segments_availableConditions(); - $availableConditionOperators = zeroBSCRM_segments_availableConditionOperators(); + $availableConditions = zeroBSCRM_segments_availableConditions(); + $availableConditionOperators = zeroBSCRM_segments_availableConditionOperators(); - foreach ($conditions as $c){ + foreach ( $conditions as $c ) { - // has proper props - if (isset($c['type']) && isset($c['operator']) && isset($c['value'])){ + // has proper props + if ( isset( $c['type'] ) && isset( $c['operator'] ) && isset( $c['value'] ) ) { - // retrieve val - $val = $c['value']; - if ($processCharacters) $val = zeroBSCRM_textProcess($val); // only pre-saving - $val = sanitize_text_field( $val ); + // retrieve val + $val = $c['value']; + if ( $processCharacters ) { + $val = zeroBSCRM_textProcess( $val ); // only pre-saving + } + $val = sanitize_text_field( $val ); - // conversions (e.g. date to uts) - $val = zeroBSCRM_segments_typeConversions($val,$c['type'],$c['operator'],'in'); + // conversions (e.g. date to uts) + $val = zeroBSCRM_segments_typeConversions( $val, $c['type'], $c['operator'], 'in' ); - // okay. (passing only expected + validated) - $addition = array( + // okay. (passing only expected + validated) + $addition = array( - 'type' => $c['type'], - 'operator' => $c['operator'], - 'value' => $val + 'type' => $c['type'], + 'operator' => $c['operator'], + 'value' => $val, - ); + ); - // ranges: + // ranges: - // int/floatval - if (isset($c['value2'])){ + // int/floatval + if ( isset( $c['value2'] ) ) { - // retrieve val2 - $val2 = $c['value2']; - if ($processCharacters) $val2 = zeroBSCRM_textProcess($val2); // only pre-saving - $val2 = sanitize_text_field( $val2 ); + // retrieve val2 + $val2 = $c['value2']; + if ( $processCharacters ) { + $val2 = zeroBSCRM_textProcess( $val2 ); // only pre-saving + } + $val2 = sanitize_text_field( $val2 ); - $addition['value2'] = $val2; + $addition['value2'] = $val2; - } + } - // daterange || datetimerange - if ( - ( - $c['operator'] == 'daterange' - || - $c['operator'] == 'datetimerange' - ) - && !empty( $val ) - ){ + // daterange || datetimerange + if ( + ( + $c['operator'] == 'daterange' + || + $c['operator'] == 'datetimerange' + ) + && ! empty( $val ) + ) { - // hmmm what if peeps use ' - ' in their date formats? This won't work if they do! + // hmmm what if peeps use ' - ' in their date formats? This won't work if they do! if ( str_contains( $val, ' - ' ) ) { $dates = explode( ' - ', $val ); @@ -310,57 +315,58 @@ function zeroBSCRM_segments_filterConditions($conditions=array(),$processCharact // Set the converted dates to UTC. $addition['value'] = zeroBSCRM_locale_dateToUTS( $value ); $addition['value2'] = zeroBSCRM_locale_dateToUTS( $value_2 ); - } - - } - - } - - // if intrange force it - if ($c['type'] == 'intrange' && !isset($addition['value2'])) $addition['value2'] = 0; - - $approvedConditions[] = $addition; - - } + } + } + } + // if intrange force it + if ( $c['type'] == 'intrange' && ! isset( $addition['value2'] ) ) { + $addition['value2'] = 0; + } - } + $approvedConditions[] = $addition; - return $approvedConditions; - - } + } + } - return array(); + return $approvedConditions; + } + return array(); } -// uses zeroBSCRM_textExpose to make query-ready strings, +// uses zeroBSCRM_textExpose to make query-ready strings, // .. because conditions are saved in encoded format, e.g. é = é -function zeroBSCRM_segments_unencodeConditions($conditions=array()){ +function zeroBSCRM_segments_unencodeConditions( $conditions = array() ) { - if (is_array($conditions) && count($conditions) > 0){ + if ( is_array( $conditions ) && count( $conditions ) > 0 ) { - $ret = array(); + $ret = array(); - foreach ($conditions as $c){ + foreach ( $conditions as $c ) { - // for now it's just value we're concerned with - $nC = $c; - if (isset($nC['value'])) $nC['value'] = zeroBSCRM_textExpose($nC['value']); - if (isset($nC['value2'])) $nC['value2'] = zeroBSCRM_textExpose($nC['value2']); + // for now it's just value we're concerned with + $nC = $c; + if ( isset( $nC['value'] ) ) { + $nC['value'] = zeroBSCRM_textExpose( $nC['value'] ); + } + if ( isset( $nC['value2'] ) ) { + $nC['value2'] = zeroBSCRM_textExpose( $nC['value2'] ); + } - // simple. - $ret[] = $nC; + // simple. + $ret[] = $nC; - } + } - return $ret; + return $ret; - } + } - return array(); + return array(); } -/* ====================================================== - / Data Validation Functions: Segments - ====================================================== */ +/* +====================================================== + / Data Validation Functions: Segments + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Database.php b/projects/plugins/crm/includes/ZeroBSCRM.Database.php index 9a1573627a8a..1d90e044a29e 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Database.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Database.php @@ -1,5 +1,6 @@ -last_error)) $zbsDB_lastError = $wpdb->last_error; - $zbsDB_creationErrors = array(); + // we log the last error before we start, in case another plugin has left an error in the buffer + $zbsDB_lastError = ''; + if ( isset( $wpdb->last_error ) ) { + $zbsDB_lastError = $wpdb->last_error; + } + $zbsDB_creationErrors = array(); - // Contacts - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['contacts'] ."( + // Contacts + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['contacts'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -124,13 +130,13 @@ function zeroBSCRM_createTables(){ PRIMARY KEY (`ID`), INDEX (`zbsc_email`, `zbsc_wpid`), KEY `zbsc_status` (`zbsc_status`) USING BTREE) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Custom Fields - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['customfields'] ."( + // Custom Fields + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['customfields'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -143,14 +149,13 @@ function zeroBSCRM_createTables(){ `zbscf_lastupdated` INT(14) NOT NULL, PRIMARY KEY (`ID`), INDEX `TYPEIDKEY` (`zbscf_objtype` ASC, `zbscf_objid` ASC, `zbscf_objkey` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Tags - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['tags'] ."( + // Tags + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['tags'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -161,13 +166,13 @@ function zeroBSCRM_createTables(){ `zbstag_created` INT(14) NOT NULL, `zbstag_lastupdated` INT(14) NOT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Tag Relationships (Links) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['taglinks'] ."( + // Tag Relationships (Links) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['taglinks'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -179,13 +184,13 @@ function zeroBSCRM_createTables(){ INDEX (`zbstl_objid`), INDEX (`zbstl_tagid`), KEY `zbstl_tagid+zbstl_objtype` (`zbstl_tagid`,`zbstl_objtype`) USING BTREE) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Settings - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['settings'] ."( + // Settings + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['settings'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -197,13 +202,13 @@ function zeroBSCRM_createTables(){ PRIMARY KEY (`ID`), INDEX `zbsset_key` (`zbsset_key`), INDEX (`zbs_owner`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Meta Key-Value pairs - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['meta'] ."( + // Meta Key-Value pairs + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['meta'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -216,13 +221,13 @@ function zeroBSCRM_createTables(){ `zbsm_lastupdated` INT(14) NOT NULL, PRIMARY KEY (`ID`), KEY `zbsm_objid+zbsm_key+zbsm_objtype` (`zbsm_objid`,`zbsm_key`,`zbsm_objtype`) USING BTREE) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - #} Segments - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['segments'] ."( + #} Segments + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['segments'] . "( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -235,13 +240,13 @@ function zeroBSCRM_createTables(){ `zbsseg_compilecount` INT NULL DEFAULT 0, `zbsseg_lastcompiled` INT(14) NOT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + " . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Segments: Conditions - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['segmentsconditions'] ."( + // Segments: Conditions + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['segmentsconditions'] . "( `ID` INT NOT NULL AUTO_INCREMENT, `zbscondition_segmentid` INT NOT NULL, `zbscondition_type` VARCHAR(50) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL, @@ -249,13 +254,13 @@ function zeroBSCRM_createTables(){ `zbscondition_val` VARCHAR(250) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NULL, `zbscondition_val_secondary` VARCHAR(250) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + " . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Admin Logs - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['adminlog'] ."( + // Admin Logs + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['adminlog'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -265,13 +270,13 @@ function zeroBSCRM_createTables(){ `zbsadmlog_str` VARCHAR(500) NULL DEFAULT NULL, `zbsadmlog_time` INT(14) NULL DEFAULT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Temporary Hashes - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['temphash'] ."( + // Temporary Hashes + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['temphash'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -284,13 +289,13 @@ function zeroBSCRM_createTables(){ `zbstemphash_lastupdated` INT(14) NOT NULL, `zbstemphash_expiry` INT(14) NOT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Object Relationships (Links) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['objlinks'] ."( + // Object Relationships (Links) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['objlinks'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -302,13 +307,13 @@ function zeroBSCRM_createTables(){ PRIMARY KEY (`ID`), INDEX (`zbsol_objid_from`), INDEX (`zbsol_objid_to`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - #} AKA (Aliases) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['aka'] ."( + #} AKA (Aliases) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['aka'] . "( `ID` INT NOT NULL AUTO_INCREMENT, `aka_type` INT NULL, `aka_id` INT NOT NULL, @@ -317,14 +322,14 @@ function zeroBSCRM_createTables(){ `aka_lastupdated` INT(14) NULL, PRIMARY KEY (`ID`), INDEX (`aka_id`, `aka_alias`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - #} External sources - // NOTE:! Modified in 2.97.5 migration - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['externalsources'] ."( + " . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + #} External sources + // NOTE:! Modified in 2.97.5 migration + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['externalsources'] . "( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -340,13 +345,13 @@ function zeroBSCRM_createTables(){ INDEX (`zbss_objid`), INDEX (`zbss_origin`), KEY `zbss_uid+zbss_source+zbss_objtype` (`zbss_uid`,`zbss_source`,`zbss_objtype`) USING BTREE) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + " . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - #} Tracking (web hit info) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['tracking'] ."( + #} Tracking (web hit info) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['tracking'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -363,13 +368,13 @@ function zeroBSCRM_createTables(){ `zbst_created` INT(14) NOT NULL, `zbst_lastupdated` INT(14) NOT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - #} Logs - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['logs'] ."( + #} Logs + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['logs'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -385,13 +390,13 @@ function zeroBSCRM_createTables(){ PRIMARY KEY (`ID`), INDEX (`zbsl_objid`), INDEX `zbsl_created` (`zbsl_created`) USING BTREE) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // System Email Templates - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['system_mail_templates'] ."( + // System Email Templates + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['system_mail_templates'] . "( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -409,13 +414,13 @@ function zeroBSCRM_createTables(){ `zbsmail_created` INT(14) NOT NULL, `zbsmail_lastupdated` INT(14) NOT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + " . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // System Email History - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['system_mail_hist'] ."( + // System Email History + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['system_mail_hist'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` int(11) DEFAULT NULL, `zbs_team` int(11) DEFAULT NULL, @@ -445,13 +450,13 @@ function zeroBSCRM_createTables(){ PRIMARY KEY (`ID`), INDEX (`zbsmail_sender_wpid`), INDEX (`zbsmail_sender_mailbox_id`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // cron Manager Logs - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['cronmanagerlogs'] ."( + // cron Manager Logs + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['cronmanagerlogs'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` int(11) DEFAULT NULL, `zbs_team` int(11) DEFAULT NULL, @@ -462,14 +467,13 @@ function zeroBSCRM_createTables(){ `jobfinished` INT(14) NOT NULL, `jobnotes` LONGTEXT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - - // Tax Table - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['tax'] ."( + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + // Tax Table + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['tax'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` int(11) DEFAULT NULL, `zbs_team` int(11) DEFAULT NULL, @@ -479,13 +483,13 @@ function zeroBSCRM_createTables(){ `zbsc_created` INT(14) NOT NULL, `zbsc_lastupdated` INT(14) NOT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Companies (DB3.0+) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['companies'] ."( + // Companies (DB3.0+) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['companies'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -520,13 +524,13 @@ function zeroBSCRM_createTables(){ INDEX `name` (`zbsco_name` ASC), INDEX `email` (`zbsco_email` ASC), INDEX `created` (`zbsco_created` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Tasks (DB3.0+) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['events'] ."( + // Tasks (DB3.0+) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['events'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -545,13 +549,13 @@ function zeroBSCRM_createTables(){ INDEX `startint` (`zbse_start` ASC), INDEX `endint` (`zbse_end` ASC), INDEX `created` (`zbse_created` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Task Reminders (DB3.0+) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['eventreminders'] ."( + // Task Reminders (DB3.0+) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['eventreminders'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -562,13 +566,13 @@ function zeroBSCRM_createTables(){ `zbser_created` INT(14) NOT NULL, `zbser_lastupdated` INT(14) NULL DEFAULT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Forms - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['forms'] ."( + // Forms + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['forms'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -598,13 +602,13 @@ function zeroBSCRM_createTables(){ PRIMARY KEY (`ID`), INDEX `title` (`zbsf_title` ASC), INDEX `created` (`zbsf_created` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Invoices - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['invoices'] ."( + // Invoices + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['invoices'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -651,13 +655,13 @@ function zeroBSCRM_createTables(){ INDEX `status` (`zbsi_status` ASC), INDEX `hash` (`zbsi_hash` ASC), INDEX `created` (`zbsi_created` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Line Items (DB3.0+) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['lineitems'] ."( + // Line Items (DB3.0+) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['lineitems'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -682,13 +686,13 @@ function zeroBSCRM_createTables(){ PRIMARY KEY (`ID`), INDEX `order` (`zbsli_order` ASC), INDEX `created` (`zbsli_created` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - // Quotes (DB3.0+) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['quotes'] ."( + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + // Quotes (DB3.0+) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['quotes'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -716,13 +720,13 @@ function zeroBSCRM_createTables(){ INDEX `hash` (`zbsq_hash` ASC), INDEX `created` (`zbsq_created` ASC), INDEX `accepted` (`zbsq_accepted` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - // Quote Templates (DB3.0+) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['quotetemplates'] ."( + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + // Quote Templates (DB3.0+) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['quotetemplates'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -739,13 +743,13 @@ function zeroBSCRM_createTables(){ PRIMARY KEY (`ID`), INDEX `title` (`zbsqt_title` ASC), INDEX `created` (`zbsqt_created` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - // Transactions (DB3.0+) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['transactions'] ."( + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + // Transactions (DB3.0+) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['transactions'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -784,13 +788,13 @@ function zeroBSCRM_createTables(){ INDEX `date` (`zbst_date` ASC), INDEX `title` (`zbst_title` ASC), INDEX `created` (`zbst_created` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); - // Security logs (used to stop repeat brute-forcing quote/inv hashes etc.) - $sql = "CREATE TABLE IF NOT EXISTS ". $ZBSCRM_t['security_log'] ."( + // Security logs (used to stop repeat brute-forcing quote/inv hashes etc.) + $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['security_log'] . '( `ID` INT NOT NULL AUTO_INCREMENT, `zbs_site` INT NULL DEFAULT NULL, `zbs_team` INT NULL DEFAULT NULL, @@ -803,10 +807,10 @@ function zeroBSCRM_createTables(){ `zbssl_reqstatus` INT(1) NULL DEFAULT NULL, `zbssl_reqtime` INT(14) NULL DEFAULT NULL, PRIMARY KEY (`ID`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); // Add table to store automation workflows. // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -876,17 +880,16 @@ function zeroBSCRM_createTables(){ } } - // no longer needed - unset($zbsDB_lastError,$zbsDB_creationErrors); - - // return any errors encountered - return $errors; + // no longer needed + unset( $zbsDB_lastError, $zbsDB_creationErrors ); + // return any errors encountered + return $errors; } #} Check existence & Create func #} WH NOTE: This could be more efficient (once we have a bunch of tabs) -function zeroBSCRM_checkTablesExist(){ +function zeroBSCRM_checkTablesExist() { global $ZBSCRM_t, $wpdb; @@ -912,36 +915,33 @@ function zeroBSCRM_checkTablesExist(){ return $create; } - /** * Attempts to run $sql through dbDelta, adding any errors to the stack as it encounters them - * */ -function zeroBSCRM_db_runDelta($sql=''){ - - global $wpdb,$zbsDB_lastError,$zbsDB_creationErrors; - +function zeroBSCRM_db_runDelta( $sql = '' ) { + + global $wpdb, $zbsDB_lastError, $zbsDB_creationErrors; + // Ensure dbDelta is available (can be missing outside of admin load order) if ( ! function_exists( 'dbDelta' ) ) { require_once ABSPATH . 'wp-admin/includes/upgrade.php'; } - // enact - dbDelta($sql); + // enact + dbDelta( $sql ); - // catch any (new) errors - if (isset($wpdb->last_error) && $wpdb->last_error !== $zbsDB_lastError) { - - // add to the stack - $zbsDB_creationErrors[] = $wpdb->last_error; + // catch any (new) errors + if ( isset( $wpdb->last_error ) && $wpdb->last_error !== $zbsDB_lastError ) { - // clock it as latest error - $zbsDB_lastError = $wpdb->last_error; + // add to the stack + $zbsDB_creationErrors[] = $wpdb->last_error; - } + // clock it as latest error + $zbsDB_lastError = $wpdb->last_error; + } } - + /** * returns availability of InnoDB MySQL Storage Engine * @@ -951,24 +951,26 @@ function zeroBSCRM_db_runDelta($sql=''){ * * @return bool (if InnoDB available) */ -function zeroBSCRM_DB_canInnoDB(){ +function zeroBSCRM_DB_canInnoDB() { if ( jpcrm_database_engine() === 'sqlite' ) { return false; } - global $wpdb; + global $wpdb; - // attempt to cycle through MySQL's ENGINES & discern InnoDB - $availableStorageEngines = $wpdb->get_results('SHOW ENGINES'); - if (is_array($availableStorageEngines)) foreach ($availableStorageEngines as $engine){ + // attempt to cycle through MySQL's ENGINES & discern InnoDB + $availableStorageEngines = $wpdb->get_results( 'SHOW ENGINES' ); + if ( is_array( $availableStorageEngines ) ) { + foreach ( $availableStorageEngines as $engine ) { - if (is_object($engine) && isset($engine->Engine) && $engine->Engine == 'InnoDB') return true; - - } - - return false; + if ( is_object( $engine ) && isset( $engine->Engine ) && $engine->Engine == 'InnoDB' ) { + return true; + } + } + } + return false; } /** @@ -1072,15 +1074,15 @@ function jpcrm_create_notifications_table() { return $table_exists; } -/* ====================================================== - / Table Creation - ====================================================== */ - - +/* +====================================================== + / Table Creation + ====================================================== */ -/* ====================================================== - Uninstall Funcs - ====================================================== */ +/* +====================================================== + Uninstall Funcs + ====================================================== */ /** * dangerous, brutal, savage. @@ -1097,29 +1099,43 @@ function zeroBSCRM_database_reset( $check_permissions = true ) { return; } - #} Brutal Reset of DB settings & removal of tables - global $wpdb, $ZBSCRM_t; - - #} DAL 2.0 CPTs - $post_types = array('zerobs_transaction', 'zerobs_customer', 'zerobs_invoice', 'zerobs_company', 'zerobs_event', 'zerobs_log', 'zerobs_quote', 'zerobs_ticket','zerobs_quo_template'); - foreach ($post_types as $post_type) $wpdb->query("DELETE FROM $wpdb->posts WHERE `post_type` = '$post_type'"); - - #} DAL 2.0 Taxonomies - $taxonomies = array('zerobscrm_tickettag', 'zerobscrm_transactiontag', 'zerobscrm_customertag','zerobscrm_worktag'); - foreach ($taxonomies as $tax) $wpdb->query("DELETE FROM $wpdb->term_taxonomy WHERE `taxonomy` = '$tax'"); - $wpdb->query("UPDATE $wpdb->term_taxonomy SET count = 0 WHERE `taxonomy` = 'zerobscrm_transactiontag'"); - - #} Floating Meta - $post_meta = array('zbs_woo_unique_ID', 'zbs_paypal_unique_ID', 'zbs_woo_unique_inv_ID', 'zbs_stripe_unique_inv_ID', 'zbs_transaction_meta', 'zbs_customer_meta','zbs_customer_ext_str','zbs_customer_ext_woo','zbs_event_meta','zbs_event_actions'); - foreach ($post_meta as $meta) $wpdb->query("DELETE FROM $wpdb->postmeta WHERE `meta_key` = '$meta'"); - $wpdb->query("DELETE FROM $wpdb->postmeta WHERE `meta_key` LIKE 'zbs_obj_ext_%';"); - - #} WP Options - Not settings/migrations, just data related options - $options = array( - 'zbs_woo_first_import_complete', 'zbs_transaction_stripe_hist', 'zbs_transaction_paypal_hist', 'zbs_pp_latest','zbscrmcsvimpresumeerrors', - 'zbs_stripe_last_charge_added','zbs_stripe_pages_imported','zbs_stripe_total_pages', - ); - foreach ($options as $option) $wpdb->query($wpdb->prepare("DELETE FROM $wpdb->options WHERE `option_name` = %s",array($option))); + #} Brutal Reset of DB settings & removal of tables + global $wpdb, $ZBSCRM_t; + + #} DAL 2.0 CPTs + $post_types = array( 'zerobs_transaction', 'zerobs_customer', 'zerobs_invoice', 'zerobs_company', 'zerobs_event', 'zerobs_log', 'zerobs_quote', 'zerobs_ticket', 'zerobs_quo_template' ); + foreach ( $post_types as $post_type ) { + $wpdb->query( "DELETE FROM $wpdb->posts WHERE `post_type` = '$post_type'" ); + } + + #} DAL 2.0 Taxonomies + $taxonomies = array( 'zerobscrm_tickettag', 'zerobscrm_transactiontag', 'zerobscrm_customertag', 'zerobscrm_worktag' ); + foreach ( $taxonomies as $tax ) { + $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE `taxonomy` = '$tax'" ); + } + $wpdb->query( "UPDATE $wpdb->term_taxonomy SET count = 0 WHERE `taxonomy` = 'zerobscrm_transactiontag'" ); + + #} Floating Meta + $post_meta = array( 'zbs_woo_unique_ID', 'zbs_paypal_unique_ID', 'zbs_woo_unique_inv_ID', 'zbs_stripe_unique_inv_ID', 'zbs_transaction_meta', 'zbs_customer_meta', 'zbs_customer_ext_str', 'zbs_customer_ext_woo', 'zbs_event_meta', 'zbs_event_actions' ); + foreach ( $post_meta as $meta ) { + $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE `meta_key` = '$meta'" ); + } + $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE `meta_key` LIKE 'zbs_obj_ext_%';" ); + + #} WP Options - Not settings/migrations, just data related options + $options = array( + 'zbs_woo_first_import_complete', + 'zbs_transaction_stripe_hist', + 'zbs_transaction_paypal_hist', + 'zbs_pp_latest', + 'zbscrmcsvimpresumeerrors', + 'zbs_stripe_last_charge_added', + 'zbs_stripe_pages_imported', + 'zbs_stripe_total_pages', + ); + foreach ( $options as $option ) { + $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->options WHERE `option_name` = %s", array( $option ) ) ); + } // phpcs:disable Generic.WhiteSpace.ScopeIndent.Incorrect,Generic.WhiteSpace.ScopeIndent.IncorrectExact,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching // DAL 3.0 tables. @@ -1127,76 +1143,108 @@ function zeroBSCRM_database_reset( $check_permissions = true ) { foreach ( $ZBSCRM_t as $k => $v ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // Do not truncate the settings. - if ( $k !== 'settings' ) { - // Copy how maybe_create_table() looks for existing tables. - if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $v ) ) ) !== $v ) { - continue; - } + // Do not truncate the settings. + if ( $k !== 'settings' ) { + // Copy how maybe_create_table() looks for existing tables. + if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $v ) ) ) !== $v ) { + continue; + } - $wpdb->query( 'TRUNCATE TABLE ' . $v ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared - } + $wpdb->query( 'TRUNCATE TABLE ' . $v ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } } // phpcs:enable Generic.WhiteSpace.ScopeIndent.Incorrect,Generic.WhiteSpace.ScopeIndent.IncorrectExact,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching - } - // dangerous, brutal, savage removal of all ZBS signs /* - ___________________ . , ; . - (___________________|~~~~~X.;' . - ' `" ' ` - TNT + ___________________ . , ; . + (___________________|~~~~~X.;' . + ' `" ' ` + TNT */ -function zeroBSCRM_database_nuke(){ - - if (current_user_can('manage_options')){ - - #} Brutal Reset of DB settings & removal of tables - global $wpdb, $ZBSCRM_t; - - #} Deactivate Extensions - zeroBSCRM_extensions_deactivateAll(); - - #} DAL 2.0 CPTs - $post_types = array('zerobs_transaction', 'zerobs_customer', 'zerobs_invoice', 'zerobs_company', 'zerobs_event', 'zerobs_log', 'zerobs_quote', 'zerobs_ticket','zerobs_quo_template'); - foreach ($post_types as $post_type) $wpdb->query("DELETE FROM $wpdb->posts WHERE `post_type` = '$post_type'"); - - #} DAL 2.0 Taxonomies - $taxonomies = array('zerobscrm_tickettag', 'zerobscrm_transactiontag', 'zerobscrm_customertag','zerobscrm_worktag'); - foreach ($taxonomies as $tax) $wpdb->query("DELETE FROM $wpdb->term_taxonomy WHERE `taxonomy` = '$tax'"); - $wpdb->query("UPDATE $wpdb->term_taxonomy SET count = 0 WHERE `taxonomy` = 'zerobscrm_transactiontag'"); - - #} Floating Meta - $post_meta = array('zbs_woo_unique_ID', 'zbs_paypal_unique_ID', 'zbs_woo_unique_inv_ID', 'zbs_stripe_unique_inv_ID', 'zbs_transaction_meta', 'zbs_customer_meta','zbs_customer_ext_str','zbs_customer_ext_woo','zbs_event_meta','zbs_event_actions'); - foreach ($post_meta as $meta) $wpdb->query("DELETE FROM $wpdb->postmeta WHERE `meta_key` = '$meta'"); - $wpdb->query("DELETE FROM $wpdb->postmeta WHERE `meta_key` LIKE 'zbs_obj_ext_%';"); - - #} WP Options - this tries to capture all, as from pre v3 we were not using formal naming conventions - $options = array( - 'zbs_woo_first_import_complete', 'zbs_transaction_stripe_hist', 'zbs_transaction_paypal_hist', 'zbs_pp_latest', - 'zbsmigrations','zbs_teleactive','zbs_update_avail','zbscptautodraftclear','zbs_wizard_run','zbscrmcsvimpresumeerrors','zbs_crm_api_key','zbs_crm_api_secret','zbs-global-perf-test','zbsmc2indexes', - 'zbs_stripe_last_charge_added','zbs_stripe_pages_imported','zbs_stripe_total_pages', - 'widget_zbs_form_widget','zerobscrmsettings','zbsmigrationpreloadcatch','zbs_db_migration_253','zerobscrmsettings_bk', - 'zbs_db_migration_300_pre_exts','zbs_db_migration_300_cftrans','zbs_db_migration_300_errstack','zbs_db_migration_300_cf','zbs_db_migration_300','zbs_children_processed','zbs_pp_latest',' _transient_timeout_zbs-nag-extension-update-now','_transient_zbs-nag-extension-update-now' - ); - foreach ($options as $option) $wpdb->query($wpdb->prepare("DELETE FROM $wpdb->options WHERE `option_name` = %s",array($option))); - - #} WP options - catchalls (be careful to only cull zbs settings here) - $wpdb->query("DELETE FROM {$wpdb->options} WHERE `option_name` LIKE 'zbsmigration%'"); - $wpdb->query("DELETE FROM {$wpdb->options} WHERE `option_name` LIKE '%zbs-db2%'"); - $wpdb->query("DELETE FROM {$wpdb->options} WHERE `option_name` LIKE '%zbs-db3%'"); - - #} DROP all DAL 3.0 tables - $ZBSCRM_t['totaltrans'] = $wpdb->prefix . "zbs_global_total_trans"; - foreach ($ZBSCRM_t as $k => $v)$wpdb->query("DROP TABLE " . $v); - - } +function zeroBSCRM_database_nuke() { -} + if ( current_user_can( 'manage_options' ) ) { + + #} Brutal Reset of DB settings & removal of tables + global $wpdb, $ZBSCRM_t; + #} Deactivate Extensions + zeroBSCRM_extensions_deactivateAll(); -/* ====================================================== - / Uninstall Funcs - ====================================================== */ + #} DAL 2.0 CPTs + $post_types = array( 'zerobs_transaction', 'zerobs_customer', 'zerobs_invoice', 'zerobs_company', 'zerobs_event', 'zerobs_log', 'zerobs_quote', 'zerobs_ticket', 'zerobs_quo_template' ); + foreach ( $post_types as $post_type ) { + $wpdb->query( "DELETE FROM $wpdb->posts WHERE `post_type` = '$post_type'" ); + } + + #} DAL 2.0 Taxonomies + $taxonomies = array( 'zerobscrm_tickettag', 'zerobscrm_transactiontag', 'zerobscrm_customertag', 'zerobscrm_worktag' ); + foreach ( $taxonomies as $tax ) { + $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE `taxonomy` = '$tax'" ); + } + $wpdb->query( "UPDATE $wpdb->term_taxonomy SET count = 0 WHERE `taxonomy` = 'zerobscrm_transactiontag'" ); + + #} Floating Meta + $post_meta = array( 'zbs_woo_unique_ID', 'zbs_paypal_unique_ID', 'zbs_woo_unique_inv_ID', 'zbs_stripe_unique_inv_ID', 'zbs_transaction_meta', 'zbs_customer_meta', 'zbs_customer_ext_str', 'zbs_customer_ext_woo', 'zbs_event_meta', 'zbs_event_actions' ); + foreach ( $post_meta as $meta ) { + $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE `meta_key` = '$meta'" ); + } + $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE `meta_key` LIKE 'zbs_obj_ext_%';" ); + + #} WP Options - this tries to capture all, as from pre v3 we were not using formal naming conventions + $options = array( + 'zbs_woo_first_import_complete', + 'zbs_transaction_stripe_hist', + 'zbs_transaction_paypal_hist', + 'zbs_pp_latest', + 'zbsmigrations', + 'zbs_teleactive', + 'zbs_update_avail', + 'zbscptautodraftclear', + 'zbs_wizard_run', + 'zbscrmcsvimpresumeerrors', + 'zbs_crm_api_key', + 'zbs_crm_api_secret', + 'zbs-global-perf-test', + 'zbsmc2indexes', + 'zbs_stripe_last_charge_added', + 'zbs_stripe_pages_imported', + 'zbs_stripe_total_pages', + 'widget_zbs_form_widget', + 'zerobscrmsettings', + 'zbsmigrationpreloadcatch', + 'zbs_db_migration_253', + 'zerobscrmsettings_bk', + 'zbs_db_migration_300_pre_exts', + 'zbs_db_migration_300_cftrans', + 'zbs_db_migration_300_errstack', + 'zbs_db_migration_300_cf', + 'zbs_db_migration_300', + 'zbs_children_processed', + 'zbs_pp_latest', + ' _transient_timeout_zbs-nag-extension-update-now', + '_transient_zbs-nag-extension-update-now', + ); + foreach ( $options as $option ) { + $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->options WHERE `option_name` = %s", array( $option ) ) ); + } + + #} WP options - catchalls (be careful to only cull zbs settings here) + $wpdb->query( "DELETE FROM {$wpdb->options} WHERE `option_name` LIKE 'zbsmigration%'" ); + $wpdb->query( "DELETE FROM {$wpdb->options} WHERE `option_name` LIKE '%zbs-db2%'" ); + $wpdb->query( "DELETE FROM {$wpdb->options} WHERE `option_name` LIKE '%zbs-db3%'" ); + + #} DROP all DAL 3.0 tables + $ZBSCRM_t['totaltrans'] = $wpdb->prefix . 'zbs_global_total_trans'; + foreach ( $ZBSCRM_t as $k => $v ) { + $wpdb->query( 'DROP TABLE ' . $v ); + } + } +} + +/* +====================================================== + / Uninstall Funcs + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Delete.php b/projects/plugins/crm/includes/ZeroBSCRM.Delete.php index 178d7570621e..3b92cb013d57 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Delete.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Delete.php @@ -1,5 +1,6 @@ - false, - 'objTypeID' => false, //5 - - // these are now retrieved from DAL centralised vars by objTypeID above, v3.0+ - // ... unless hard typed here. - 'objType' => false, //transaction - 'singular' => false, //Transaction - 'plural' => false, //Transactions - 'listViewSlug' => false, //manage-transactions - 'langLabels' => array( - - ) - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - // NOTE: here these vars are passed like: - // $this->objID - // .. NOT - // $objID + private $objTypeID = false; // ZBS_TYPE_CONTACT - v3.0+ + + // following now FILLED OUT by objTypeID above, v3.0+ + private $objType = false; // 'contact' + private $singular = false; + private $plural = false; + private $listViewSlug = false; + private $langLabels = false; + + private $stage = 1; // 1 = 'are you sure', 2 = 'deleted' + private $canDelete = 1; // if no perms -1 + + // this only applies to contacts (v3.0) + private $killChildren = false; + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + 'objID' => false, + 'objTypeID' => false, // 5 + + // these are now retrieved from DAL centralised vars by objTypeID above, v3.0+ + // ... unless hard typed here. + 'objType' => false, // transaction + 'singular' => false, // Transaction + 'plural' => false, // Transactions + 'listViewSlug' => false, // manage-transactions + 'langLabels' => array(), + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + // NOTE: here these vars are passed like: + // $this->objID + // .. NOT + // $objID global $zbs; // we load from DAL defaults, if objTypeID passed (overriding anything passed, if empty/false) if ( isset( $this->objTypeID ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - $objTypeID = (int)$this->objTypeID; - if ($objTypeID > 0){ - - // obj type (contact) - $objTypeStr = $zbs->DAL->objTypeKey($objTypeID); - if ((!isset($this->objType) || $this->objType == false) && !empty($objTypeStr)) $this->objType = $objTypeStr; - - // singular - $objSingular = $zbs->DAL->typeStr($objTypeID); - if ((!isset($this->singular) || $this->singular == false) && !empty($objSingular)) $this->singular = $objSingular; - - // plural - $objPlural = $zbs->DAL->typeStr($objTypeID,true); - if ((!isset($this->plural) || $this->plural == false) && !empty($objPlural)) $this->plural = $objPlural; - - // listViewSlug - $objSlug = $zbs->DAL->listViewSlugFromObjID($objTypeID); - if ((!isset($this->listViewSlug) || $this->listViewSlug == false) && !empty($objSlug)) $this->listViewSlug = $objSlug; - - } + $objTypeID = (int) $this->objTypeID; + if ( $objTypeID > 0 ) { + + // obj type (contact) + $objTypeStr = $zbs->DAL->objTypeKey( $objTypeID ); + if ( ( ! isset( $this->objType ) || $this->objType == false ) && ! empty( $objTypeStr ) ) { + $this->objType = $objTypeStr; + } + + // singular + $objSingular = $zbs->DAL->typeStr( $objTypeID ); + if ( ( ! isset( $this->singular ) || $this->singular == false ) && ! empty( $objSingular ) ) { + $this->singular = $objSingular; + } + + // plural + $objPlural = $zbs->DAL->typeStr( $objTypeID, true ); + if ( ( ! isset( $this->plural ) || $this->plural == false ) && ! empty( $objPlural ) ) { + $this->plural = $objPlural; + } + + // listViewSlug + $objSlug = $zbs->DAL->listViewSlugFromObjID( $objTypeID ); + if ( ( ! isset( $this->listViewSlug ) || $this->listViewSlug == false ) && ! empty( $objSlug ) ) { + $this->listViewSlug = $objSlug; + } + } } - // if objid - load $post - $this->loadObject(); + // if objid - load $post + $this->loadObject(); - // check perms - if (!zeroBSCRM_permsObjType($this->objTypeID)) $this->canDelete = false; + // check perms + if ( ! zeroBSCRM_permsObjType( $this->objTypeID ) ) { + $this->canDelete = false; + } - // check if it actually exists - if (!is_array($this->obj) || !isset($this->obj['id'])) $this->canDelete = false; + // check if it actually exists + if ( ! is_array( $this->obj ) || ! isset( $this->obj['id'] ) ) { + $this->canDelete = false; + } - // anything to save? - if ($this->canDelete) $this->catchPost(); + // anything to save? + if ( $this->canDelete ) { + $this->catchPost(); + } } - // automatically, generically, loads the single obj - public function loadObject(){ + // automatically, generically, loads the single obj + public function loadObject() { - // if objid - load $post - if (isset($this->objID) && !empty($this->objID) && $this->objID > 0) { + // if objid - load $post + if ( isset( $this->objID ) && ! empty( $this->objID ) && $this->objID > 0 ) { global $zbs; // DAL3 we can use generic getSingle if ( $this->objTypeID > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - // this gets $zbs->DAL->contacts->getSingle() - $this->obj = $zbs->DAL->getObjectLayerByType($this->objTypeID)->getSingle($this->objID); + // this gets $zbs->DAL->contacts->getSingle() + $this->obj = $zbs->DAL->getObjectLayerByType( $this->objTypeID )->getSingle( $this->objID ); } else { - // DAL2 - // customer currently only - $this->obj = zeroBS_getCustomer($this->objID); + // DAL2 + // customer currently only + $this->obj = zeroBS_getCustomer( $this->objID ); } } } - public function catchPost(){ - - // If post, fire do_action - // DAL3 this gets postType switched to objType - if (isset($_POST['zbs-delete-form-master']) && $_POST['zbs-delete-form-master'] == $this->objTypeID){ - - // CHECK NONCE - if ( wp_verify_nonce( $_POST['zbs-delete-nonce'], 'delete-nonce' ) ) { - - // got any extras? e.g. kill children? - if (isset($_POST['zbs-delete-kill-children'])){ - if ($_POST['zbs-delete-kill-children'] == 'no') $this->killChildren = false; - if ($_POST['zbs-delete-kill-children'] == 'yes') $this->killChildren = true; - } - - // verify + delete - if (isset($_POST['zbs-delete-id']) && $_POST['zbs-delete-id'] == $this->objID){ - - - global $zbs; - - // got orphans? - $saveOrphans = true; if ($this->killChildren) $saveOrphans = false; - - // legit, delete - switch ($this->objTypeID){ - - case ZBS_TYPE_CONTACT: - - // delete - $deleted = $zbs->DAL->contacts->deleteContact(array( - 'id' => $this->objID, - 'saveOrphans' => $saveOrphans - )); - - break; - - case ZBS_TYPE_COMPANY: - - // delete - $deleted = $zbs->DAL->companies->deleteCompany(array( - 'id' => $this->objID, - 'saveOrphans' => $saveOrphans - )); - - - break; - - case ZBS_TYPE_QUOTE: - - // delete - $deleted = $zbs->DAL->quotes->deleteQuote(array( - 'id' => $this->objID, - 'saveOrphans' => $saveOrphans - )); - - break; - - case ZBS_TYPE_INVOICE: - - // delete - $deleted = $zbs->DAL->invoices->deleteInvoice(array( - 'id' => $this->objID, - 'saveOrphans' => $saveOrphans - )); - - break; - - case ZBS_TYPE_TRANSACTION: - - // delete - $deleted = $zbs->DAL->transactions->deleteTransaction(array( - 'id' => $this->objID, - 'saveOrphans' => $saveOrphans - )); - - break; - - case ZBS_TYPE_FORM: - - // delete - $deleted = $zbs->DAL->forms->deleteForm(array( - 'id' => $this->objID, - 'saveOrphans' => $saveOrphans - )); - - break; - - case ZBS_TYPE_TASK: - - // for now always kill links - $saveOrphans = false; - - // delete - $deleted = $zbs->DAL->events->deleteEvent(array( - 'id' => $this->objID, - 'saveOrphans' => $saveOrphans - )); - - break; - - case ZBS_TYPE_QUOTETEMPLATE: - - // delete - $deleted = $zbs->DAL->quotetemplates->deleteQuotetemplate(array( - 'id' => $this->objID, - 'saveOrphans' => $saveOrphans - )); - - break; - - } - - // fire it - do_action('zerobs_delete_'.$this->objType, $this->objID, $this->obj); - - // set $stage +1 (as only get here if posted ^) - $this->stage = 2; - - } - - } - - } - } - - public function drawView(){ + public function catchPost() { + + // If post, fire do_action + // DAL3 this gets postType switched to objType + if ( isset( $_POST['zbs-delete-form-master'] ) && $_POST['zbs-delete-form-master'] == $this->objTypeID ) { + + // CHECK NONCE + if ( wp_verify_nonce( $_POST['zbs-delete-nonce'], 'delete-nonce' ) ) { + + // got any extras? e.g. kill children? + if ( isset( $_POST['zbs-delete-kill-children'] ) ) { + if ( $_POST['zbs-delete-kill-children'] == 'no' ) { + $this->killChildren = false; + } + if ( $_POST['zbs-delete-kill-children'] == 'yes' ) { + $this->killChildren = true; + } + } + + // verify + delete + if ( isset( $_POST['zbs-delete-id'] ) && $_POST['zbs-delete-id'] == $this->objID ) { + + global $zbs; + + // got orphans? + $saveOrphans = true; + if ( $this->killChildren ) { + $saveOrphans = false; + } + + // legit, delete + switch ( $this->objTypeID ) { + + case ZBS_TYPE_CONTACT: + // delete + $deleted = $zbs->DAL->contacts->deleteContact( + array( + 'id' => $this->objID, + 'saveOrphans' => $saveOrphans, + ) + ); + + break; + + case ZBS_TYPE_COMPANY: + // delete + $deleted = $zbs->DAL->companies->deleteCompany( + array( + 'id' => $this->objID, + 'saveOrphans' => $saveOrphans, + ) + ); + + break; + + case ZBS_TYPE_QUOTE: + // delete + $deleted = $zbs->DAL->quotes->deleteQuote( + array( + 'id' => $this->objID, + 'saveOrphans' => $saveOrphans, + ) + ); + + break; + + case ZBS_TYPE_INVOICE: + // delete + $deleted = $zbs->DAL->invoices->deleteInvoice( + array( + 'id' => $this->objID, + 'saveOrphans' => $saveOrphans, + ) + ); + + break; + + case ZBS_TYPE_TRANSACTION: + // delete + $deleted = $zbs->DAL->transactions->deleteTransaction( + array( + 'id' => $this->objID, + 'saveOrphans' => $saveOrphans, + ) + ); + + break; + + case ZBS_TYPE_FORM: + // delete + $deleted = $zbs->DAL->forms->deleteForm( + array( + 'id' => $this->objID, + 'saveOrphans' => $saveOrphans, + ) + ); + + break; + + case ZBS_TYPE_TASK: + // for now always kill links + $saveOrphans = false; + + // delete + $deleted = $zbs->DAL->events->deleteEvent( + array( + 'id' => $this->objID, + 'saveOrphans' => $saveOrphans, + ) + ); + + break; + + case ZBS_TYPE_QUOTETEMPLATE: + // delete + $deleted = $zbs->DAL->quotetemplates->deleteQuotetemplate( + array( + 'id' => $this->objID, + 'saveOrphans' => $saveOrphans, + ) + ); + + break; + + } + + // fire it + do_action( 'zerobs_delete_' . $this->objType, $this->objID, $this->obj ); + + // set $stage +1 (as only get here if posted ^) + $this->stage = 2; + + } + } + } + } - // check - if (empty($this->objType) || empty($this->listViewSlug) || empty($this->singular) || empty($this->plural)){ + public function drawView() { - return 'Error.'; - } + // check + if ( empty( $this->objType ) || empty( $this->listViewSlug ) || empty( $this->singular ) || empty( $this->plural ) ) { - global $zbs; + return 'Error.'; + } + global $zbs; - ?>
-
+ ?>
+ -
- + plural,'There has been a problem retrieving your '.$this->singular.', if this issue persists, please ask your administrator to reach out to Jetpack CRM.','disabled warning sign','zbsCantLoadData'); - echo zeroBSCRM_UI2_messageHTML('warning hidden','Error Retrieving '.$this->singular,'There has been a problem retrieving your '.$this->singular.', if this issue persists, please ask your administrator to reach out to Jetpack CRM.','disabled warning sign','zbsCantLoadDataSingle'); - - ?> -
- -
+ echo zeroBSCRM_UI2_messageHTML( 'warning hidden', 'Error Retrieving ' . $this->plural, 'There has been a problem retrieving your ' . $this->singular . ', if this issue persists, please ask your administrator to reach out to Jetpack CRM.', 'disabled warning sign', 'zbsCantLoadData' ); + echo zeroBSCRM_UI2_messageHTML( 'warning hidden', 'Error Retrieving ' . $this->singular, 'There has been a problem retrieving your ' . $this->singular . ', if this issue persists, please ask your administrator to reach out to Jetpack CRM.', 'disabled warning sign', 'zbsCantLoadDataSingle' ); - +
+ +
- if (count($zbs->pageMessages) > 0){ - - #} Updated Msgs - // was doing like this, but need control over styling - // do_action( 'zerobs_updatemsg_contact'); - // so for now just using global :) - echo '
'; + pageMessages as $msg){ + if ( count( $zbs->pageMessages ) > 0 ) { - // for now these can be any html :) - echo $msg; + #} Updated Msgs + // was doing like this, but need control over styling + // do_action( 'zerobs_updatemsg_contact'); + // so for now just using global :) + echo '
'; - } + foreach ( $zbs->pageMessages as $msg ) { - echo '
'; + // for now these can be any html :) + echo $msg; - } + } + echo '
'; + } - ?> + ?> -
+
- canDelete){ + if ( ! $this->canDelete ) { - // no perms msg + // no perms msg - ?> -
-
- singular.'.','disabled warning sign','zbsCantDelete'); ?> -
-
- +
+
+ singular . '.', 'disabled warning sign', 'zbsCantDelete' ); ?> +
+
+ stage){ + } else { - case 2: + // switch based on stage + switch ( $this->stage ) { - // deleted ?> + case 2: + // deleted + ?> -
+
-
+
-
- -
-
- -
-

singular ).' '. esc_html__('was successfully deleted.',"zero-bs-crm"); ?>

-

+ +

+
+ +
+

singular ) . ' ' . esc_html__( 'was successfully deleted.', 'zero-bs-crm' ); ?>

+

+ objTypeID); + // delete / back buttons + $backUrl = jpcrm_esc_link( 'list', -1, $this->objTypeID ); - // output - echo ''. esc_html__('Back to','zero-bs-crm').' '. esc_html( $this->plural ).''; - - ?>

-
-
-
+ // output + echo '' . esc_html__( 'Back to', 'zero-bs-crm' ) . ' ' . esc_html( $this->plural ) . ''; -
+ ?> +

+
+
+
-
- break; + + case 1: + // are you sure? + ?> -
+
-
+
- - + + -
- -
-
- -
-

singular ).'?'; ?>

- + +
+
+ +
+

singular ) . '?'; ?>

+ objTypeID,$objectTypesWithChildren)){ + // contact needs extra check: + if ( in_array( $this->objTypeID, $objectTypesWithChildren ) ) { - // ouput explanation (what children will go) - switch ($this->objTypeID){ + // ouput explanation (what children will go) + switch ( $this->objTypeID ) { - case ZBS_TYPE_CONTACT: - case ZBS_TYPE_COMPANY: + case ZBS_TYPE_CONTACT: + case ZBS_TYPE_COMPANY: ?> '; - esc_html_e( 'Shall I also delete the associated Contacts, Invoices, Quotes, Transactions, and Tasks?', 'zero-bs-crm' ); - echo '
'; - esc_html_e( '(This cannot be undone!)', 'zero-bs-crm' ); - echo '

'; - break; + echo '

'; + esc_html_e( 'Shall I also delete the associated Contacts, Invoices, Quotes, Transactions, and Tasks?', 'zero-bs-crm' ); + echo '
'; + esc_html_e( '(This cannot be undone!)', 'zero-bs-crm' ); + echo '

'; + break; } ?> -

- -

-

objID,$this->objTypeID); - - // output - echo ''; - echo ' '. esc_html__('Back to','zero-bs-crm').' '. esc_html( $this->singular ).' ('. esc_html__('Cancel','zero-bs-crm').')'; - - ?>

-
-
-
- -
+

+ +

+ +

+ objID, $this->objTypeID ); - default: + // output + echo ''; + echo ' ' . esc_html__( 'Back to', 'zero-bs-crm' ) . ' ' . esc_html( $this->singular ) . ' (' . esc_html__( 'Cancel', 'zero-bs-crm' ) . ')'; - // smt broken! - echo 'Error!'; + ?> +

+
+
+
- break; +
+ + } + } // / can delete -
+ ?> - -
+ - " /> - + + - - } // /draw func + }; + + + DAL->segments->getSegment($segmentID, true); - - $matchtype = !empty( $segment['matchtype'] ) ? $segment['matchtype'] : ''; - - if (isset($segment) && isset($segment['id'])) { - // checks out - $newSegment = false; - } else { - // no perms/doesn't checkout - $segment = false; - } - - // retrieve conditions/helpers - $available_conditions = zeroBSCRM_segments_availableConditions(); - $available_conditions_by_category = zeroBSCRM_segments_availableConditions( true ); - $available_condition_operators = zeroBSCRM_segments_availableConditionOperators(); - $available_tags_contacts = $zbs->DAL->getTagsForObjType( array( 'objtypeid'=>ZBS_TYPE_CONTACT ) ); - $available_tags_transactions = $zbs->DAL->getTagsForObjType( array( 'objtypeid' => ZBS_TYPE_TRANSACTION ) ); - $availableStatuses = zeroBSCRM_getCustomerStatuses(true); - - #} Refresh 2 - ?>
- - - - - -
- -
- -

- - -
- -
- - - -
- getErrorCode( $segment['error'] ); - if ($error_code && isset( $error_code['user_message'] ) ) { - $error_message = $error_code['user_message']; - } else { - // error code not present in global error-code array, show code - $error_message = $segment['error']; - } - echo zeroBSCRM_UI2_messageHTML( - 'warning', - __('Segment Warning', 'zero-bs-crm'), - __('There is an issue with this segment:', 'zero-bs-crm') . '
' . $error_message, - 'warning', - 'segment-condition-error' - ); ?> -
- - - -
- -
+function zeroBSCRM_html_addEditSegment( $potentialID = -1 ) { + + global $zbs; + + #} New or edit + $newSegment = true; + + // potential + $segmentID = (int) $potentialID; + + // attempt retrieve (including has rights) + $segment = $zbs->DAL->segments->getSegment( $segmentID, true ); + + $matchtype = ! empty( $segment['matchtype'] ) ? $segment['matchtype'] : ''; + + if ( isset( $segment ) && isset( $segment['id'] ) ) { + // checks out + $newSegment = false; + } else { + // no perms/doesn't checkout + $segment = false; + } + + // retrieve conditions/helpers + $available_conditions = zeroBSCRM_segments_availableConditions(); + $available_conditions_by_category = zeroBSCRM_segments_availableConditions( true ); + $available_condition_operators = zeroBSCRM_segments_availableConditionOperators(); + $available_tags_contacts = $zbs->DAL->getTagsForObjType( array( 'objtypeid' => ZBS_TYPE_CONTACT ) ); + $available_tags_transactions = $zbs->DAL->getTagsForObjType( array( 'objtypeid' => ZBS_TYPE_TRANSACTION ) ); + $availableStatuses = zeroBSCRM_getCustomerStatuses( true ); + + #} Refresh 2 + ?>
+ + + + + +
+ +
+ +

+ + +
+ +
+ + + +
+ getErrorCode( $segment['error'] ); + if ( $error_code && isset( $error_code['user_message'] ) ) { + $error_message = $error_code['user_message']; + } else { + // error code not present in global error-code array, show code + $error_message = $segment['error']; + } + echo zeroBSCRM_UI2_messageHTML( + 'warning', + __( 'Segment Warning', 'zero-bs-crm' ), + __( 'There is an issue with this segment:', 'zero-bs-crm' ) . '
' . $error_message, + 'warning', + 'segment-condition-error' + ); + ?> +
+ + + +
+ +
- - -

- -
- -
- -
-
- -
- -
- -

any or all of the above conditions?', 'zero-bs-crm' ); ?>

- -
- -

- -
+ + + + +

+ +
+ +
+ +
+
+ +
+ +
+ +

any or all of the above conditions?', 'zero-bs-crm' ); ?>

+ +
+ +

+ +
- + // export + if ( zeroBSCRM_permsExport() ) { + ?> - -
-
- - - - - - -
+
+
+ + + + + + +
+ db) - // For dates, convert to UTS here. (EXCEPT FOR daterange/datetimerange!, dealing with that in zeroBSCRM_segments_filterConditions for now) - if ($direction == 'in' && $operator != 'daterange' && $operator != 'datetimerange' && $operator != 'nextdays' && $operator != 'previousdays' ) { - switch ($available_conditions[$type]['conversion']) { - case 'date-to-uts': + // INBOUND (e.g. post -> db) + // For dates, convert to UTS here. (EXCEPT FOR daterange/datetimerange!, dealing with that in zeroBSCRM_segments_filterConditions for now) + if ( $direction == 'in' && $operator != 'daterange' && $operator != 'datetimerange' && $operator != 'nextdays' && $operator != 'previousdays' ) { + switch ( $available_conditions[ $type ]['conversion'] ) { + case 'date-to-uts': $local_date_time = new DateTime( $value, wp_timezone() ); $local_date_time->setTimezone( new DateTimeZone( 'UTC' ) ); $value = $local_date_time->format( 'Y-m-d H:i' ); - // convert date to uts - $value = zeroBSCRM_locale_dateToUTS($value, true); - - // for cases where we're saying 'after' {timestamp} we add 1 second - if ($operator == 'after') { - $value += 1; - } - - break; - } - - } elseif ( $direction == 'out' && $operator != 'nextdays' && $operator != 'previousdays' ) { - // OUTBOUND (e.g. exposing dates in segment editor) - - // OUTBOUND (e.g. exposing dates in segment editor) - switch ($available_conditions[$type]['conversion']) { - - case 'date-to-uts': - - // for cases where we're saying 'after' {timestamp} we add 1 second - // here we retract that addition - if ($operator == 'after') { - $value -= 1; - } - - // convert uts back to date + // convert date to uts + $value = zeroBSCRM_locale_dateToUTS( $value, true ); + + // for cases where we're saying 'after' {timestamp} we add 1 second + if ( $operator == 'after' ) { + $value += 1; + } + + break; + } + } elseif ( $direction == 'out' && $operator != 'nextdays' && $operator != 'previousdays' ) { + // OUTBOUND (e.g. exposing dates in segment editor) + + // OUTBOUND (e.g. exposing dates in segment editor) + switch ( $available_conditions[ $type ]['conversion'] ) { + + case 'date-to-uts': + // for cases where we're saying 'after' {timestamp} we add 1 second + // here we retract that addition + if ( $operator == 'after' ) { + $value -= 1; + } + + // convert uts back to date $value = zeroBSCRM_date_i18n_plusTime( 'Y-m-d', $value ); - break; - } - - } - } - } + break; + } + } + } + } - return $value; + return $value; } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Edit.php b/projects/plugins/crm/includes/ZeroBSCRM.Edit.php index 9e12f7a4daf3..a5526d32a271 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Edit.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Edit.php @@ -1,5 +1,6 @@ - false, - 'objTypeID' => false, //5 - - // these are now retrieved from DAL centralised vars by objTypeID above, v3.0+ - // ... unless hard typed here. - 'objType' => false, //transaction - 'singular' => false, //Transaction - 'plural' => false, //Transactions - 'listViewSlug' => false, //manage-transactions - - 'langLabels' => array( - - ), - 'extraBoxes' => '' // html for extra boxes e.g. upsells :) - - ); foreach ($defaultArgs as $argK => $argV){ $this->$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $this->$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$this->$argK = $newData;} else { $this->$argK = $args[$argK]; } } } - #} =========== / LOAD ARGS ============= - - // NOTE: here these vars are passed like: - // $this->objID - // .. NOT - // $objID +class zeroBSCRM_Edit { + + private $objID = false; + private $obj = false; + private $objTypeID = false; // ZBS_TYPE_CONTACT - v3.0+ + + // following now FILLED OUT by objTypeID above, v3.0+ + private $objType = false; // 'contact' + private $singular = false; + private $plural = false; + // renamed listViewSlug v3.0+ private $postPage = false; + private $listViewSlug = false; + + private $langLabels = false; + private $bulkActions = false; + private $sortables = false; + private $unsortables = false; + private $extraBoxes = ''; + private $isGhostRecord = false; + private $isNewRecord = false; + + // permissions + private $has_permissions_to_edit = false; + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + 'objID' => false, + 'objTypeID' => false, // 5 + + // these are now retrieved from DAL centralised vars by objTypeID above, v3.0+ + // ... unless hard typed here. + 'objType' => false, // transaction + 'singular' => false, // Transaction + 'plural' => false, // Transactions + 'listViewSlug' => false, // manage-transactions + + 'langLabels' => array(), + 'extraBoxes' => '', // html for extra boxes e.g. upsells :) + + ); + foreach ( $defaultArgs as $argK => $argV ) { + $this->$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $this->$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$this->$argK = $newData; + } else { + $this->$argK = $args[ $argK ]; } + } + } + #} =========== / LOAD ARGS ============= + // NOTE: here these vars are passed like: + // $this->objID + // .. NOT + // $objID - global $zbs; + global $zbs; - // we load from DAL defaults, if objTypeID passed (overriding anything passed, if empty/false) + // we load from DAL defaults, if objTypeID passed (overriding anything passed, if empty/false) if ( isset( $this->objTypeID ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - $objTypeID = (int)$this->objTypeID; - if ($objTypeID > 0){ - - // obj type (contact) - $objTypeStr = $zbs->DAL->objTypeKey($objTypeID); - if ((!isset($this->objType) || $this->objType == false) && !empty($objTypeStr)) $this->objType = $objTypeStr; - - // singular - $objSingular = $zbs->DAL->typeStr($objTypeID); - if ((!isset($this->singular) || $this->singular == false) && !empty($objSingular)) $this->singular = $objSingular; - - // plural - $objPlural = $zbs->DAL->typeStr($objTypeID,true); - if ((!isset($this->plural) || $this->plural == false) && !empty($objPlural)) $this->plural = $objPlural; - - // listViewSlug - $objSlug = $zbs->DAL->listViewSlugFromObjID($objTypeID); - if ((!isset($this->listViewSlug) || $this->listViewSlug == false) && !empty($objSlug)) $this->listViewSlug = $objSlug; - - } - } else $this->isNewRecord = true; + $objTypeID = (int) $this->objTypeID; + if ( $objTypeID > 0 ) { - // if objid - load $post - $this->loadObject(); - - // Ghost? - if ($this->objID !== -1 && !$this->isNewRecord && isset($this->objTypeID) && !is_array($this->obj)) $this->isGhostRecord = true; - - // anything to save? - $this->catchPost(); + // obj type (contact) + $objTypeStr = $zbs->DAL->objTypeKey( $objTypeID ); + if ( ( ! isset( $this->objType ) || $this->objType == false ) && ! empty( $objTypeStr ) ) { + $this->objType = $objTypeStr; + } - // include any 'post learn menu' code - add_action( 'zerobscrm-subtop-menu', array( $this, 'post_learn_menu_output' ) ); + // singular + $objSingular = $zbs->DAL->typeStr( $objTypeID ); + if ( ( ! isset( $this->singular ) || $this->singular == false ) && ! empty( $objSingular ) ) { + $this->singular = $objSingular; + } - } + // plural + $objPlural = $zbs->DAL->typeStr( $objTypeID, true ); + if ( ( ! isset( $this->plural ) || $this->plural == false ) && ! empty( $objPlural ) ) { + $this->plural = $objPlural; + } - // automatically, generically, loads the single obj - public function loadObject(){ + // listViewSlug + $objSlug = $zbs->DAL->listViewSlugFromObjID( $objTypeID ); + if ( ( ! isset( $this->listViewSlug ) || $this->listViewSlug == false ) && ! empty( $objSlug ) ) { + $this->listViewSlug = $objSlug; + } + } + } else { + $this->isNewRecord = true; + } - // if objid - load $post - if ( isset( $this->objID ) && !empty( $this->objID ) && $this->objID > 0 ) { + // if objid - load $post + $this->loadObject(); - global $zbs; + // Ghost? + if ( $this->objID !== -1 && ! $this->isNewRecord && isset( $this->objTypeID ) && ! is_array( $this->obj ) ) { + $this->isGhostRecord = true; + } - if ( $this->objTypeID > 0 ){ + // anything to save? + $this->catchPost(); - // got permissions? - if ( zeroBSCRM_permsObjType( $this->objTypeID ) ){ + // include any 'post learn menu' code + add_action( 'zerobscrm-subtop-menu', array( $this, 'post_learn_menu_output' ) ); + } - // this gets $zbs->DAL->contacts->getSingle() - $this->obj = $zbs->DAL->getObjectLayerByType($this->objTypeID)->getSingle($this->objID); + // automatically, generically, loads the single obj + public function loadObject() { - // has permissions - $this->has_permissions_to_edit = true; + // if objid - load $post + if ( isset( $this->objID ) && ! empty( $this->objID ) && $this->objID > 0 ) { - } + global $zbs; - } + if ( $this->objTypeID > 0 ) { - } + // got permissions? + if ( zeroBSCRM_permsObjType( $this->objTypeID ) ) { - } + // this gets $zbs->DAL->contacts->getSingle() + $this->obj = $zbs->DAL->getObjectLayerByType( $this->objTypeID )->getSingle( $this->objID ); - public function catchPost(){ + // has permissions + $this->has_permissions_to_edit = true; - // If post, fire do_action - if (isset($_POST['zbs-edit-form-master']) && $_POST['zbs-edit-form-master'] == $this->objType){ + } + } + } + } - // make sure we have perms to save - if ($this->preChecks()) { - // fire it - do_action('zerobs_save_'.$this->objType, $this->objID, $this->obj); - // after catching post, we need to reload data :) (as may be changed) - $this->loadObject(); - } + public function catchPost() { + // If post, fire do_action + if ( isset( $_POST['zbs-edit-form-master'] ) && $_POST['zbs-edit-form-master'] == $this->objType ) { - } - } + // make sure we have perms to save + if ( $this->preChecks() ) { + // fire it + do_action( 'zerobs_save_' . $this->objType, $this->objID, $this->obj ); + // after catching post, we need to reload data :) (as may be changed) + $this->loadObject(); + } + } + } - // check ownership, access etc. - public function preChecks(){ + // check ownership, access etc. + public function preChecks() { global $zbs; @@ -205,216 +221,227 @@ public function preChecks(){ $this->preCheckFail( sprintf( __( 'You do not have permission to edit this %s.', 'zero-bs-crm' ), $zbs->DAL->typeStr( $this->objTypeID ) ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase return false; - } - if ( !$this->has_permissions_to_edit ){ - // user does not have a role which can edit this object type - $this->preCheckFail( sprintf( __( 'You do not have permission to edit this %s.', 'zero-bs-crm' ), $zbs->DAL->typeStr( $this->objTypeID ) ) ); - return false; - - } - if ( $is_malformed_obj ) { - // not a perms issue, so show general error - $this->preCheckFail( sprintf( __( 'There was an error loading this %s.', 'zero-bs-crm' ), $zbs->DAL->typeStr( $this->objTypeID ) ) ); - return false; - } - - } - - //load if is legit - return true; - } - - public function preCheckFail($msg=''){ - - echo '
'; - echo zeroBSCRM_UI2_messageHTML('warning',$msg,'','disabled warning sign','failRetrieving'); - echo '
'; - - // grim quick hack to hide save button - echo ''; - } + } + if ( ! $this->has_permissions_to_edit ) { + // user does not have a role which can edit this object type + $this->preCheckFail( sprintf( __( 'You do not have permission to edit this %s.', 'zero-bs-crm' ), $zbs->DAL->typeStr( $this->objTypeID ) ) ); + return false; - /* - * Code added to this function will be called just after the learn menu is output - * (where we're on an edit page) - */ - public function post_learn_menu_output(){ + } + if ( $is_malformed_obj ) { + // not a perms issue, so show general error + $this->preCheckFail( sprintf( __( 'There was an error loading this %s.', 'zero-bs-crm' ), $zbs->DAL->typeStr( $this->objTypeID ) ) ); + return false; + } + } - // put screen options out - zeroBSCRM_screenOptionsPanel(); + // load if is legit + return true; + } - } + public function preCheckFail( $msg = '' ) { - public function drawEditView(){ + echo '
'; + echo zeroBSCRM_UI2_messageHTML( 'warning', $msg, '', 'disabled warning sign', 'failRetrieving' ); + echo '
'; - // run pre-checks which verify ownership etc. - $okayToDraw = $this->preChecks(); + // grim quick hack to hide save button + echo ''; + } - // draw if okay :) - if ($okayToDraw) $this->drawEditViewHTML(); + /* + * Code added to this function will be called just after the learn menu is output + * (where we're on an edit page) + */ + public function post_learn_menu_output() { - } + // put screen options out + zeroBSCRM_screenOptionsPanel(); + } - public function drawEditViewHTML(){ + public function drawEditView() { - if (empty($this->objType) || empty($this->listViewSlug) || empty($this->singular) || empty($this->plural)){ + // run pre-checks which verify ownership etc. + $okayToDraw = $this->preChecks(); + // draw if okay :) + if ( $okayToDraw ) { + $this->drawEditViewHTML(); + } + } - echo zeroBSCRM_UI2_messageHTML('warning','Error Retrieving '.$this->singular,'There has been a problem retrieving your '.$this->singular.', if this issue persists, please contact support.','disabled warning sign','zbsCantLoadData'); - return false; + public function drawEditViewHTML() { - } + if ( empty( $this->objType ) || empty( $this->listViewSlug ) || empty( $this->singular ) || empty( $this->plural ) ) { - // catch id's passed where no contact exists for them. - if ($this->isGhostRecord){ + echo zeroBSCRM_UI2_messageHTML( 'warning', 'Error Retrieving ' . $this->singular, 'There has been a problem retrieving your ' . $this->singular . ', if this issue persists, please contact support.', 'disabled warning sign', 'zbsCantLoadData' ); + return false; - // brutal hide, then msg #ghostrecord - ?> -
singular,'There does not appear to be a '.$this->singular.' with this ID.','disabled warning sign','zbsCantLoadData'); - ?>
isGhostRecord ) { - // catch if is new record + hide zbs-nav-view - if ($this->isNewRecord){ + // brutal hide, then msg #ghostrecord + ?> +
+ singular, 'There does not appear to be a ' . $this->singular . ' with this ID.', 'disabled warning sign', 'zbsCantLoadData' ); + ?> +
+ isNewRecord ) { - global $zbs; + // just hide button via css. Should just stop this via learn in time + ?> + + preChecks(); + } + global $zbs; - ?>
+ // run pre-checks which verify ownership etc. + $this->preChecks(); -
- +
- echo zeroBSCRM_UI2_messageHTML('warning hidden','Error Retrieving '.$this->plural,'There has been a problem retrieving your '.$this->singular.', if this issue persists, please ask your administrator to reach out to Jetpack CRM.','disabled warning sign','zbsCantLoadData'); - echo zeroBSCRM_UI2_messageHTML('warning hidden','Error Retrieving '.$this->singular,'There has been a problem retrieving your '.$this->singular.', if this issue persists, please ask your administrator to reach out to Jetpack CRM.','disabled warning sign','zbsCantLoadDataSingle'); - - ?> -
- -
+
+ plural, 'There has been a problem retrieving your ' . $this->singular . ', if this issue persists, please ask your administrator to reach out to Jetpack CRM.', 'disabled warning sign', 'zbsCantLoadData' ); + echo zeroBSCRM_UI2_messageHTML( 'warning hidden', 'Error Retrieving ' . $this->singular, 'There has been a problem retrieving your ' . $this->singular . ', if this issue persists, please ask your administrator to reach out to Jetpack CRM.', 'disabled warning sign', 'zbsCantLoadDataSingle' ); - if (count($zbs->pageMessages) > 0){ - - #} Updated Msgs - // was doing like this, but need control over styling - // do_action( 'zerobs_updatemsg_contact'); - // so for now just using global :) - echo '
'; + ?> +
+ +
- foreach ($zbs->pageMessages as $msg){ + pageMessages ) > 0 ) { - } + #} Updated Msgs + // was doing like this, but need control over styling + // do_action( 'zerobs_updatemsg_contact'); + // so for now just using global :) + echo '
'; - echo '
'; + foreach ( $zbs->pageMessages as $msg ) { - } + // for now these can be any html :) + echo $msg; + } + echo '
'; - ?> + } -
+ ?> +
- -
- objType.'-edit', 'normal', $this->obj ); - ?> + +
-
- -
- objType . '-edit', 'normal', $this->obj ); + ?> - #} Sidebar metaboxes - zeroBSCRM_do_meta_boxes( 'zbs-add-edit-'.$this->objType.'-edit', 'side', $this->obj ); +
+ +
+ + #} Sidebar metaboxes + zeroBSCRM_do_meta_boxes( 'zbs-add-edit-' . $this->objType . '-edit', 'side', $this->obj ); - - extraBoxes; ?> - -
-
+ ?> - -
-
+ + extraBoxes; ?> + +
+
- - } // /draw func + }; + + + $max_iv_length ) { - $iv = substr( $iv, $max_iv_length ); - } + // catch cases where IV length is wrong + // openssl truncates already, but this catches it before logging + $max_iv_length = openssl_cipher_iv_length( ZBS_ENCRYPTION_METHOD ); + if ( strlen( $iv ) > $max_iv_length ) { + $iv = substr( $iv, $max_iv_length ); + } - if ( $action == 'encrypt' ) { - $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv); - } else if( $action == 'decrypt' ) { - $output = openssl_decrypt( $string, $encrypt_method, $key, 0, $iv); - } - return $output; + if ( $action == 'encrypt' ) { + $output = openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ); + } elseif ( $action == 'decrypt' ) { + $output = openssl_decrypt( $string, $encrypt_method, $key, 0, $iv ); + } + return $output; } function zeroBSCRM_get_iv( $hide_deprecation = false ) { - if ( !$hide_deprecation ) zeroBSCRM_DEPRECATEDMSG('CRM Function Deprecated in v5.3: zeroBSCRM_get_iv'); + if ( ! $hide_deprecation ) { + zeroBSCRM_DEPRECATEDMSG( 'CRM Function Deprecated in v5.3: zeroBSCRM_get_iv' ); + } static $iv = null; if ( null === $iv ) { - $iv = pack( 'C*', ...array_slice( unpack( 'C*', AUTH_KEY ), 0, openssl_cipher_iv_length( ZBS_ENCRYPTION_METHOD ) ) ); + $iv = pack( 'C*', ...array_slice( unpack( 'C*', AUTH_KEY ), 0, openssl_cipher_iv_length( ZBS_ENCRYPTION_METHOD ) ) ); } return $iv; } -function zeroBSCRM_encrypt( $string, $key, $hide_deprecation = false ){ +function zeroBSCRM_encrypt( $string, $key, $hide_deprecation = false ) { - if ( !$hide_deprecation ) zeroBSCRM_DEPRECATEDMSG('CRM Function Deprecated in v5.3: zeroBSCRM_encrypt'); + if ( ! $hide_deprecation ) { + zeroBSCRM_DEPRECATEDMSG( 'CRM Function Deprecated in v5.3: zeroBSCRM_encrypt' ); + } return zeroBSCRM_encryption_unsafe_process( 'encrypt', $string, $key, zeroBSCRM_get_iv() ); - } function zeroBSCRM_decrypt( $string, $key, $hide_deprecation = false ) { - if ( !$hide_deprecation ) zeroBSCRM_DEPRECATEDMSG('CRM Function Deprecated in v5.3: zeroBSCRM_decrypt'); + if ( ! $hide_deprecation ) { + zeroBSCRM_DEPRECATEDMSG( 'CRM Function Deprecated in v5.3: zeroBSCRM_decrypt' ); + } return zeroBSCRM_encryption_unsafe_process( 'decrypt', $string, $key, zeroBSCRM_get_iv() ); - } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.ErrorCodes.php b/projects/plugins/crm/includes/ZeroBSCRM.ErrorCodes.php index da37f8313ad2..b531fcf4fd34 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.ErrorCodes.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.ErrorCodes.php @@ -1,5 +1,6 @@ - array( - - // available options: - 'area' - 'objtype' (use * if all) - 'defaultmsg' - - ) - 301 => array( - 'area' => 'dal' - 'objtype' => ZBS_TYPE_COMPANY, - 'description' => 'unique_check_fail' - ) - - */ - - - // ================ PHP DAL - - 301 => array( - 'area' => 'dal', - 'objtype' => '*', - 'description' => 'unique_check_fail' - ), - 302 => array( - 'area' => 'dal', - 'objtype' => '*', - 'description' => 'update_fail' - ), - 303 => array( - 'area' => 'dal', - 'objtype' => '*', - 'description' => 'insert_fail' - ), - 304 => array( - 'area' => 'dal', - 'objtype' => '*', - 'description' => 'empty_not_allowed' - ), - 305 => array( - 'area' => 'dal', - 'objtype' => '*', - 'description' => 'field_abbreviated' - ), - 306 => array( - 'area' => 'dal', - 'objtype' => '*', - 'description' => 'failed_creating_tables' - ), - 307 => array( - 'area' => 'dal', - 'objtype' => '*', - 'description' => 'invalid_alias' - ), - - - // ================ Migrations - - 701 => array( - 'area' => 'migrations', - 'objtype' => '*', - 'description' => 'unavoidable_merge' - ), - - 702 => array( - 'area' => 'migrations', - 'objtype' => '*', - 'description' => 'invoice_total_discrepancy' - ), - - 703 => array( - 'area' => 'migrations', - 'objtype' => '*', - 'description' => 'open_fail' - ), - - 704 => array( - 'area' => 'migrations', - 'objtype' => '*', - 'description' => 'migration_ajax_fail' - ), - - 710 => array( - 'area' => 'migrations', - 'objtype' => '*', - 'description' => 'extension_activation' - ), - - 711 => array( - 'area' => 'migrations', - 'objtype' => '*', - 'description' => 'close_fail' - ), - - - - // ================ Exceptions - 'segment_condition_produces_no_args' => array( - 'area' => 'segments', - 'objtype' => 'segment', - 'description' => 'segment_condition_produces_no_args', - 'user_message' => __( 'This segment was created using custom conditions (e.g. from the Advanced Segment extension), and it appears that those conditions have been removed. Please reactivate any related extensions or functionality, or remove the custom conditions this segment.', 'zero-bs-crm' ) - ), - - ); + */ +function zeroBSCRM_errorCodes() { + + return array( + + /* + Example: + + key => array( + + // available options: + 'area' + 'objtype' (use * if all) + 'defaultmsg' + + ) + 301 => array( + 'area' => 'dal' + 'objtype' => ZBS_TYPE_COMPANY, + 'description' => 'unique_check_fail' + ) + + */ + + // ================ PHP DAL + + 301 => array( + 'area' => 'dal', + 'objtype' => '*', + 'description' => 'unique_check_fail', + ), + 302 => array( + 'area' => 'dal', + 'objtype' => '*', + 'description' => 'update_fail', + ), + 303 => array( + 'area' => 'dal', + 'objtype' => '*', + 'description' => 'insert_fail', + ), + 304 => array( + 'area' => 'dal', + 'objtype' => '*', + 'description' => 'empty_not_allowed', + ), + 305 => array( + 'area' => 'dal', + 'objtype' => '*', + 'description' => 'field_abbreviated', + ), + 306 => array( + 'area' => 'dal', + 'objtype' => '*', + 'description' => 'failed_creating_tables', + ), + 307 => array( + 'area' => 'dal', + 'objtype' => '*', + 'description' => 'invalid_alias', + ), + + // ================ Migrations + + 701 => array( + 'area' => 'migrations', + 'objtype' => '*', + 'description' => 'unavoidable_merge', + ), + + 702 => array( + 'area' => 'migrations', + 'objtype' => '*', + 'description' => 'invoice_total_discrepancy', + ), + + 703 => array( + 'area' => 'migrations', + 'objtype' => '*', + 'description' => 'open_fail', + ), + + 704 => array( + 'area' => 'migrations', + 'objtype' => '*', + 'description' => 'migration_ajax_fail', + ), + + 710 => array( + 'area' => 'migrations', + 'objtype' => '*', + 'description' => 'extension_activation', + ), + + 711 => array( + 'area' => 'migrations', + 'objtype' => '*', + 'description' => 'close_fail', + ), + + // ================ Exceptions + 'segment_condition_produces_no_args' => array( + 'area' => 'segments', + 'objtype' => 'segment', + 'description' => 'segment_condition_produces_no_args', + 'user_message' => __( 'This segment was created using custom conditions (e.g. from the Advanced Segment extension), and it appears that those conditions have been removed. Please reactivate any related extensions or functionality, or remove the custom conditions this segment.', 'zero-bs-crm' ), + ), + + ); } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.ExternalSources.php b/projects/plugins/crm/includes/ZeroBSCRM.ExternalSources.php index 933b0cdef581..25ee313d0860 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.ExternalSources.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.ExternalSources.php @@ -1,5 +1,6 @@ - 'fa-stripe'); - return $external_sources; - } + public function register_external_source($external_sources = array()){ + $external_sources['str'] = array('Stripe', 'ico' => 'fa-stripe'); + return $external_sources; + } - #} adds this as an external source - add_filter('zbs_approved_sources' , array($this, 'register_external_source'), 10); + #} adds this as an external source + add_filter('zbs_approved_sources' , array($this, 'register_external_source'), 10); - */ - global $zbscrmApprovedExternalSources; - $zbscrmApprovedExternalSources = zeroBS_baseExternalSources(); + */ + global $zbscrmApprovedExternalSources; + $zbscrmApprovedExternalSources = zeroBS_baseExternalSources(); // 2.97.7 wrapped these in a func so they can be less affected than a global ? :/ // this is called directly now in core to load them, rather than using the global $zbscrmApprovedExternalSources; -// ... global $zbscrmApprovedExternalSources is still set though, for backward compat, (not sure if some older ext using?) +// ... global $zbscrmApprovedExternalSources is still set though, for backward compat, (not sure if some older ext using?) function zeroBS_baseExternalSources() { $external_sources = array( - 'woo' => array( 'WooCommerce', 'ico' => 'fa-shopping-cart' ), // fa-shopping-cart is default :) no woo yet. - 'pay' => array( 'PayPal', 'ico' => 'fa-paypal' ), - 'env' => array( 'Envato', 'ico' => 'fa-envira' ), // fa-envira is a look-alike http://fontawesome.io/icon/envira/. - 'csv' => array( 'CSV Import', 'ico' => 'fa-file-text' ), - 'form' => array( 'Form Capture', 'ico' => 'fa-wpforms'), - 'gra' => array( 'Gravity Forms', 'ico' => 'fa-wpforms'), - 'api' => array( 'API', 'ico' => 'fa-random'), - 'wpa' => array( 'WorldPay', 'ico' => 'fa-credit-card'), - 'str' => array( 'Stripe', 'ico' => 'fa-credit-card'), - 'wordpress' => array( 'WordPress', 'ico' => 'fa-wpforms'), - 'cf7' => array( 'Contact Form 7', 'ico' => 'fa-wpforms'), - 'jetpack_form' => array( 'Jetpack Contact Form', 'ico' => 'fa-wpforms' ), - - // Discontinued - //'jvz' => array( 'JV Zoo', 'ico' => 'fa-paypal' ), + 'woo' => array( + 'WooCommerce', + 'ico' => 'fa-shopping-cart', + ), // fa-shopping-cart is default :) no woo yet. + 'pay' => array( + 'PayPal', + 'ico' => 'fa-paypal', + ), + 'env' => array( + 'Envato', + 'ico' => 'fa-envira', + ), // fa-envira is a look-alike http://fontawesome.io/icon/envira/. + 'csv' => array( + 'CSV Import', + 'ico' => 'fa-file-text', + ), + 'form' => array( + 'Form Capture', + 'ico' => 'fa-wpforms', + ), + 'gra' => array( + 'Gravity Forms', + 'ico' => 'fa-wpforms', + ), + 'api' => array( + 'API', + 'ico' => 'fa-random', + ), + 'wpa' => array( + 'WorldPay', + 'ico' => 'fa-credit-card', + ), + 'str' => array( + 'Stripe', + 'ico' => 'fa-credit-card', + ), + 'wordpress' => array( + 'WordPress', + 'ico' => 'fa-wpforms', + ), + 'cf7' => array( + 'Contact Form 7', + 'ico' => 'fa-wpforms', + ), + 'jetpack_form' => array( + 'Jetpack Contact Form', + 'ico' => 'fa-wpforms', + ), + + // Discontinued + // 'jvz' => array( 'JV Zoo', 'ico' => 'fa-paypal' ), ); $external_sources = apply_filters( 'jpcrm_register_external_sources', $external_sources ); @@ -63,94 +98,89 @@ function zeroBS_baseExternalSources() { // phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound } - /* * Simple external source info return based on key */ -function jpcrm_get_external_source_info( $source_key ){ +function jpcrm_get_external_source_info( $source_key ) { - $external_sources = zeroBS_baseExternalSources(); + $external_sources = zeroBS_baseExternalSources(); - if ( isset( $external_sources[ $source_key ] ) ){ + if ( isset( $external_sources[ $source_key ] ) ) { - return $external_sources[ $source_key ]; - - } + return $external_sources[ $source_key ]; - return false; + } + + return false; } // Returns a simplified 1 line explanation of an external source -function zeroBS_getExternalSourceTitle($srcKey='',$srcUID=''){ - - // some old hard typed: - - switch ($srcKey){ - - case 'pay': #} paypal - - return ' PayPal:
'.$srcUID.''; - - break; +function zeroBS_getExternalSourceTitle( $srcKey = '', $srcUID = '' ) { - #case 'woo': #} Woo - case 'env': + // some old hard typed: - return ' Envato:
'.$srcUID.''; + switch ( $srcKey ) { - break; + case 'pay': #} paypal + return ' PayPal:
' . $srcUID . ''; - case 'form': + break; - return ' Form Capture:
'.$srcUID.''; + #case 'woo': #} Woo + case 'env': + return ' Envato:
' . $srcUID . ''; - break; + break; - case 'csv': + case 'form': + return ' Form Capture:
' . $srcUID . ''; - return ' CSV Import:
'.$srcUID.''; + break; - break; + case 'csv': + return ' CSV Import:
' . $srcUID . ''; - case 'gra': + break; - return ' Gravity Forms:
'.$srcUID.''; + case 'gra': + return ' Gravity Forms:
' . $srcUID . ''; - break; - - case 'api': + break; - return ' API:
'.$srcUID.''; + case 'api': + return ' API:
' . $srcUID . ''; - break; + break; - default: + default: + // see if in $zbs->external_sources + global $zbs; - // see if in $zbs->external_sources - global $zbs; + if ( isset( $zbs->external_sources[ $srcKey ] ) ) { - if (isset($zbs->external_sources[$srcKey])){ + $ico = 'fa-users'; + if ( is_array( $zbs->external_sources[ $srcKey ] ) && isset( $zbs->external_sources[ $srcKey ]['ico'] ) ) { + $ico = $zbs->external_sources[ $srcKey ]['ico']; + } + $name = ucwords( str_replace( '_', ' ', $srcKey ) ); + if ( is_array( $zbs->external_sources[ $srcKey ] ) && isset( $zbs->external_sources[ $srcKey ][0] ) ) { + $name = $zbs->external_sources[ $srcKey ][0]; + } - $ico = 'fa-users'; if (is_array($zbs->external_sources[$srcKey]) && isset($zbs->external_sources[$srcKey]['ico'])) $ico = $zbs->external_sources[$srcKey]['ico']; - $name = ucwords(str_replace('_',' ',$srcKey)); if (is_array($zbs->external_sources[$srcKey]) && isset($zbs->external_sources[$srcKey][0])) $name = $zbs->external_sources[$srcKey][0]; + return ' ' . $name . ':
' . $srcUID . ''; - return ' '.$name.':
'.$srcUID.''; + } else { - } else { + #} Generic for now + return ' ' . ucwords( str_replace( '_', ' ', $srcKey ) ) . ':
' . $srcUID . ''; - #} Generic for now - return ' '.ucwords(str_replace('_',' ',$srcKey)).':
'.$srcUID.''; + } - } + break; - break; - - - - } + } } - /* * Renders HTML describing external sources for an object * Primarily used in object 'external source' metaboxes @@ -158,26 +188,27 @@ function zeroBS_getExternalSourceTitle($srcKey='',$srcUID=''){ * @param int $object_id (crm contact, company, invoice, or transaction) * @param int $object_type_id */ -function jpcrm_render_external_sources_by_id( $object_id, $object_type_id ){ +function jpcrm_render_external_sources_by_id( $object_id, $object_type_id ) { - global $zbs; + global $zbs; - // get sources, if any - $external_sources = $zbs->DAL->getExternalSources( -1, array( - - 'objectID' => $object_id, - 'objectType' => $object_type_id, - 'grouped_by_source' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + // get sources, if any + $external_sources = $zbs->DAL->getExternalSources( + -1, + array( - )); + 'objectID' => $object_id, + 'objectType' => $object_type_id, + 'grouped_by_source' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - // render - jpcrm_render_external_sources_info( $external_sources, $object_id, $object_type_id ); + ) + ); + // render + jpcrm_render_external_sources_info( $external_sources, $object_id, $object_type_id ); } - /* * Renders HTML describing external sources for an object * Primarily used in object 'external source' metaboxes @@ -185,79 +216,79 @@ function jpcrm_render_external_sources_by_id( $object_id, $object_type_id ){ * * @param array $external_sources (requires these in 'grouped' format) */ -function jpcrm_render_external_sources_info( $external_sources, $object_id, $object_type_id ){ +function jpcrm_render_external_sources_info( $external_sources, $object_id, $object_type_id ) { + + global $zbs; + + // got any to render? + if ( isset( $external_sources ) && is_array( $external_sources ) && count( $external_sources ) > 0 ) { - global $zbs; - - // got any to render? - if ( isset( $external_sources ) && is_array( $external_sources ) && count( $external_sources ) > 0 ){ - - if ( count( $external_sources ) > 0 ){ + if ( count( $external_sources ) > 0 ) { - echo '
'; + echo '
'; - // first cycle through sources and stack by origin key (e.g. 'woo'), - // so we can group if multiple. + // first cycle through sources and stack by origin key (e.g. 'woo'), + // so we can group if multiple. + foreach ( $external_sources as $external_source_group_key => $external_source_group ) { - foreach ( $external_sources as $external_source_group_key => $external_source_group ){ + // 'woo' => array( 'WooCommerce', 'ico' => 'fa-shopping-cart' ) + $external_source_group_info = jpcrm_get_external_source_info( $external_source_group_key ); - // 'woo' => array( 'WooCommerce', 'ico' => 'fa-shopping-cart' ) - $external_source_group_info = jpcrm_get_external_source_info( $external_source_group_key ); + // got multiple of same source? (e.g. woo customer with multiple orders) + $multiple_in_group = ( count( $external_source_group ) > 1 ); - // got multiple of same source? (e.g. woo customer with multiple orders) - $multiple_in_group = ( count( $external_source_group ) > 1 ); + // show group header + echo '
'; - // show group header - echo '
'; + echo '
' . ( is_array( $external_source_group_info ) ? '  ' . $external_source_group_info[0] : $external_source_group_key ) . '
'; - echo '
' . ( is_array( $external_source_group_info ) ? '  ' . $external_source_group_info[0] : $external_source_group_key ) . '
'; + foreach ( $external_source_group as $external_source ) { - foreach ( $external_source_group as $external_source ){ + #} Display a "source" + echo '
'; - #} Display a "source" - echo '
'; + $uid = $external_source['uid']; - $uid = $external_source['uid']; + // company + CSV means uid will be a useless hash, so replace that with name if we have + if ( $external_source['source'] == 'csv' && $object_type_id == ZBS_TYPE_COMPANY ) { + $uid = __( 'Imported based on name', 'zero-bs-crm' ); + } - // company + CSV means uid will be a useless hash, so replace that with name if we have - if ( $external_source['source'] == 'csv' && $object_type_id == ZBS_TYPE_COMPANY ){ - $uid = __( 'Imported based on name', 'zero-bs-crm' ); - } + // build basic + $external_source_html = zeroBS_getExternalSourceTitle( $external_source['source'], $uid ); - // build basic - $external_source_html = zeroBS_getExternalSourceTitle( $external_source['source'], $uid ); + // filter any given title - can be wired in to give links (e.g. wooc orders) + $external_source_html = apply_filters( + 'zbs_external_source_infobox_line', + $external_source_html, + array( + 'objtype' => $object_type_id, + 'objid' => $object_id, + 'source' => $external_source['source'], + 'origin' => $external_source['origin'], + 'unique_id' => $uid, + ) + ); - // filter any given title - can be wired in to give links (e.g. wooc orders) - $external_source_html = apply_filters( 'zbs_external_source_infobox_line', $external_source_html, - array( - 'objtype' => $object_type_id, - 'objid' => $object_id, - 'source' => $external_source['source'], - 'origin' => $external_source['origin'], - 'unique_id' => $uid - ) - ); + // output + echo $external_source_html; - // output - echo $external_source_html; + echo '
'; - echo '
'; + } - } - - echo '
'; + echo '
'; - } - - echo '
'; + } - } + echo '
'; - } else { + } + } else { - // manually added - echo '

' . esc_html( sprintf( __( '%s added manually.', 'zero-bs-crm' ), ucwords( $zbs->DAL->objTypeKey( $object_type_id ) ) ) ) . '

'; + // manually added + echo '

' . esc_html( sprintf( __( '%s added manually.', 'zero-bs-crm' ), ucwords( $zbs->DAL->objTypeKey( $object_type_id ) ) ) ) . '

'; - } + } } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.FileUploads.php b/projects/plugins/crm/includes/ZeroBSCRM.FileUploads.php index e1da05740878..459a389cf16e 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.FileUploads.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.FileUploads.php @@ -1,5 +1,6 @@ - array('application/pdf'), - 'doc' => array('application/msword'), - 'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document'), - 'ppt' => array('application/vnd.ms-powerpointtd>'), - 'pptx' => array('application/vnd.openxmlformats-officedocument.presentationml.presentation'), - 'xls' => array('application/vnd.ms-excel'), - 'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'), - 'csv' => array('text/csv'), - 'png' => array('image/png'), - 'jpg' => array('image/jpeg'), - 'jpeg' => array('image/jpeg'), - 'gif' => array('image/gif'), - 'mp3' => array('audio/mpeg'), - 'txt' => array('text/plain'), - 'zip' => array('application/zip', 'application/x-compressed-zip'), - 'mp4' => array('video/mp4') - # plus 'any' - ); - } - - /* +function zeroBSCRM_returnMimeTypes() { + return array( + 'pdf' => array( 'application/pdf' ), + 'doc' => array( 'application/msword' ), + 'docx' => array( 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ), + 'ppt' => array( 'application/vnd.ms-powerpointtd>' ), + 'pptx' => array( 'application/vnd.openxmlformats-officedocument.presentationml.presentation' ), + 'xls' => array( 'application/vnd.ms-excel' ), + 'xlsx' => array( 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ), + 'csv' => array( 'text/csv' ), + 'png' => array( 'image/png' ), + 'jpg' => array( 'image/jpeg' ), + 'jpeg' => array( 'image/jpeg' ), + 'gif' => array( 'image/gif' ), + 'mp3' => array( 'audio/mpeg' ), + 'txt' => array( 'text/plain' ), + 'zip' => array( 'application/zip', 'application/x-compressed-zip' ), + 'mp4' => array( 'video/mp4' ), + # plus 'any' + ); +} + + /* * Returns the extension for the provided mimetype, false otherwise. */ - function jpcrm_return_ext_for_mimetype( $mimetype ) { - global $zbs; - $all_types = $zbs->acceptable_mime_types; - - foreach( $all_types as $extension => $ext_mimetypes ) { - foreach( $ext_mimetypes as $this_mimetype ) { - if ( $this_mimetype === $mimetype ) { - return $extension; - } +function jpcrm_return_ext_for_mimetype( $mimetype ) { + global $zbs; + $all_types = $zbs->acceptable_mime_types; + + foreach ( $all_types as $extension => $ext_mimetypes ) { + foreach ( $ext_mimetypes as $this_mimetype ) { + if ( $this_mimetype === $mimetype ) { + return $extension; } } - - return false; } -/* ====================================================== - / Acceptible Mime Types - ====================================================== */ - - - + return false; +} +/* +====================================================== + / Acceptible Mime Types + ====================================================== */ -/* ====================================================== - File Upload Related Funcs - ====================================================== */ +/* +====================================================== + File Upload Related Funcs + ====================================================== */ // str e.g. .pdf, .xls - function zeroBS_acceptableFileTypeListStr(){ +function zeroBS_acceptableFileTypeListStr() { - $ret = ''; - - global $zbs; + $ret = ''; - #} Retrieve settings - $settings = $zbs->settings->getAll(); - - if (isset($settings['filetypesupload'])) { + global $zbs; - if (isset($settings['filetypesupload']['all']) && $settings['filetypesupload']['all'] == 1){ + #} Retrieve settings + $settings = $zbs->settings->getAll(); - $ret = __( 'All File Types', 'zero-bs-crm' ); + if ( isset( $settings['filetypesupload'] ) ) { - } else { + if ( isset( $settings['filetypesupload']['all'] ) && $settings['filetypesupload']['all'] == 1 ) { - foreach ($settings['filetypesupload'] as $filetype => $enabled){ + $ret = __( 'All File Types', 'zero-bs-crm' ); - if (isset($settings['filetypesupload'][$filetype]) && $enabled == 1) { + } else { - if (!empty($ret)) $ret .= ', '; + foreach ( $settings['filetypesupload'] as $filetype => $enabled ) { - $ret .= '.'.$filetype; + if ( isset( $settings['filetypesupload'][ $filetype ] ) && $enabled == 1 ) { + if ( ! empty( $ret ) ) { + $ret .= ', '; } - } + $ret .= '.' . $filetype; + } } - } + } - if (empty($ret)) $ret = 'No Uploads Allowed'; - - return $ret; + if ( empty( $ret ) ) { + $ret = 'No Uploads Allowed'; } - function zeroBS_acceptableFileTypeListArr(){ + return $ret; +} - $ret = array(); - - global $zbs; +function zeroBS_acceptableFileTypeListArr() { - #} Retrieve settings - $settings = $zbs->settings->getAll(); - - if (isset($settings['filetypesupload'])) - foreach ($settings['filetypesupload'] as $filetype => $enabled){ + $ret = array(); - if (isset($settings['filetypesupload'][$filetype]) && $enabled == 1) $ret[] = '.'.$filetype; + global $zbs; - } + #} Retrieve settings + $settings = $zbs->settings->getAll(); - return $ret; + if ( isset( $settings['filetypesupload'] ) ) { + foreach ( $settings['filetypesupload'] as $filetype => $enabled ) { + + if ( isset( $settings['filetypesupload'][ $filetype ] ) && $enabled == 1 ) { + $ret[] = '.' . $filetype; + } + } } - function zeroBS_acceptableFileTypeMIMEArr(){ + return $ret; +} - $ret = array(); - - global $zbs; +function zeroBS_acceptableFileTypeMIMEArr() { - #} Retrieve settings - $settings = $zbs->settings->getAll(); - - // if all, pass that - if ( isset( $settings['filetypesupload'] ) && isset($settings['filetypesupload']['all']) && $settings['filetypesupload']['all'] == 1){ + $ret = array(); - return array('all'=>1); + global $zbs; - } - if (isset($settings['filetypesupload'])) { - if (isset($settings['filetypesupload']['all']) && $settings['filetypesupload']['all'] == 1) { - // add all - foreach ($settings['filetypesupload'] as $filetype => $enabled){ - $ret = array_merge( $ret, $zbs->acceptable_mime_types[$filetype] ); - } - } else { - // individual - foreach ($settings['filetypesupload'] as $filetype => $enabled) { - if ( isset( $settings['filetypesupload'][$filetype] ) && $enabled == 1 ) { - $ret = array_merge( $ret, $zbs->acceptable_mime_types[$filetype] ); - } + #} Retrieve settings + $settings = $zbs->settings->getAll(); + + // if all, pass that + if ( isset( $settings['filetypesupload'] ) && isset( $settings['filetypesupload']['all'] ) && $settings['filetypesupload']['all'] == 1 ) { + + return array( 'all' => 1 ); + + } + if ( isset( $settings['filetypesupload'] ) ) { + if ( isset( $settings['filetypesupload']['all'] ) && $settings['filetypesupload']['all'] == 1 ) { + // add all + foreach ( $settings['filetypesupload'] as $filetype => $enabled ) { + $ret = array_merge( $ret, $zbs->acceptable_mime_types[ $filetype ] ); + } + } else { + // individual + foreach ( $settings['filetypesupload'] as $filetype => $enabled ) { + if ( isset( $settings['filetypesupload'][ $filetype ] ) && $enabled == 1 ) { + $ret = array_merge( $ret, $zbs->acceptable_mime_types[ $filetype ] ); } } } - - return $ret; } + return $ret; +} + /** - * Returns an array with all the mime types accepted for uploads from + * Returns an array with all the mime types accepted for uploads from * contacts. */ - function jpcrm_acceptable_filetype_mime_array_from_contacts() { - global $zbs; +function jpcrm_acceptable_filetype_mime_array_from_contacts() { + global $zbs; - $ret = array(); - $settings = $zbs->settings->getAll(); - if ( isset( $settings['filetypesupload'] ) ) { - foreach ( $settings['filetypesupload'] as $filetype => $enabled ) { - if ( - $enabled == 1 - && isset( $settings['filetypesupload'][$filetype] ) - && isset( $zbs->acceptable_mime_types[$filetype] ) - ) { - $ret = array_merge( $ret, $zbs->acceptable_mime_types[$filetype] ); - } + $ret = array(); + $settings = $zbs->settings->getAll(); + if ( isset( $settings['filetypesupload'] ) ) { + foreach ( $settings['filetypesupload'] as $filetype => $enabled ) { + if ( $enabled == 1 + && isset( $settings['filetypesupload'][ $filetype ] ) + && isset( $zbs->acceptable_mime_types[ $filetype ] ) + ) { + $ret = array_merge( $ret, $zbs->acceptable_mime_types[ $filetype ] ); } } - - return $ret; } + return $ret; +} - function jpcrm_acceptable_file_type_list_str_for_contact() { - $ret = ''; - - global $zbs; +function jpcrm_acceptable_file_type_list_str_for_contact() { + $ret = ''; - $settings = $zbs->settings->getAll(); - - if ( isset( $settings['filetypesupload'] ) && is_array( $settings['filetypesupload'] ) ) { - foreach ($settings['filetypesupload'] as $filetype => $enabled){ - if (isset($settings['filetypesupload'][$filetype]) && $enabled == 1 && $filetype !== 'all') { - if (!empty($ret)) $ret .= ', '; - $ret .= '.'.$filetype; + global $zbs; + + $settings = $zbs->settings->getAll(); + + if ( isset( $settings['filetypesupload'] ) && is_array( $settings['filetypesupload'] ) ) { + foreach ( $settings['filetypesupload'] as $filetype => $enabled ) { + if ( isset( $settings['filetypesupload'][ $filetype ] ) && $enabled == 1 && $filetype !== 'all' ) { + if ( ! empty( $ret ) ) { + $ret .= ', '; } - } + $ret .= '.' . $filetype; + } } - if (empty($ret)) $ret = 'No Uploads Allowed'; - - return $ret; + } + if ( empty( $ret ) ) { + $ret = 'No Uploads Allowed'; } + return $ret; +} #} removes a link to file (quote, invoice, other) // not always customer id... sometimes inv/co etc. - function zeroBS_removeFile($objectID=-1,$fileType='',$fileURL=''){ - - if ( current_user_can( 'admin_zerobs_customers' ) ) { //only admin can do this too (extra security layer) +function zeroBS_removeFile( $objectID = -1, $fileType = '', $fileURL = '' ) { - global $zbs; + if ( current_user_can( 'admin_zerobs_customers' ) ) { // only admin can do this too (extra security layer) - if ($objectID !== -1 && !empty($fileURL)){ - - /* centralised into zeroBSCRM_files_getFiles - switch ($fileType){ + global $zbs; - case 'customer': + if ( $objectID !== -1 && ! empty( $fileURL ) ) { - $filesArrayKey = 'zbs_customer_files'; + /* + centralised into zeroBSCRM_files_getFiles + switch ($fileType){ - break; - case 'quotes': + case 'customer': - $filesArrayKey = 'zbs_customer_quotes'; + $filesArrayKey = 'zbs_customer_files'; - break; - case 'invoices': + break; + case 'quotes': - $filesArrayKey = 'zbs_customer_invoices'; + $filesArrayKey = 'zbs_customer_quotes'; - break; - } */ + break; + case 'invoices': - #} good? - // zeroBSCRM_files_getFiles if (isset($filesArrayKey)){ - if (in_array($fileType, array('customer','quotes','invoices','company'))){ + $filesArrayKey = 'zbs_customer_invoices'; - #} First remove list reference: + break; + } */ - #} any change? - $changeFlag = false; $fileObjToDelete = false; + #} good? + // zeroBSCRM_files_getFiles if (isset($filesArrayKey)){ + if ( in_array( $fileType, array( 'customer', 'quotes', 'invoices', 'company' ) ) ) { - #} Load files arr - $filesList = zeroBSCRM_files_getFiles($fileType,$objectID); + #} First remove list reference: + #} any change? + $changeFlag = false; + $fileObjToDelete = false; - if (is_array($filesList) && count($filesList) > 0){ + #} Load files arr + $filesList = zeroBSCRM_files_getFiles( $fileType, $objectID ); - #} defs - $ret = array(); - - #} Cycle through and remove any with this url - lame, but works for now - foreach ($filesList as $fileObj){ + if ( is_array( $filesList ) && count( $filesList ) > 0 ) { - if ($fileObj['url'] != $fileURL) - $ret[] = $fileObj; - else { - $fileObjToDelete = $fileObj; - $changeFlag = true; + #} defs + $ret = array(); - // also, if the removed file(s) are logged in any slots, clear the slot :) - $slot = zeroBSCRM_fileslots_fileSlot($fileObj['file'],$objectID,ZBS_TYPE_CONTACT); - if ($slot !== false && !empty($slot)){ - zeroBSCRM_fileslots_clearFileSlot($slot,$objectID,ZBS_TYPE_CONTACT); - } - } + #} Cycle through and remove any with this url - lame, but works for now + foreach ( $filesList as $fileObj ) { - } + if ( $fileObj['url'] != $fileURL ) { + $ret[] = $fileObj; + } else { + $fileObjToDelete = $fileObj; + $changeFlag = true; - if ($changeFlag) { - zeroBSCRM_files_updateFiles($fileType,$objectID,$ret); + // also, if the removed file(s) are logged in any slots, clear the slot :) + $slot = zeroBSCRM_fileslots_fileSlot( $fileObj['file'], $objectID, ZBS_TYPE_CONTACT ); + if ( $slot !== false && ! empty( $slot ) ) { + zeroBSCRM_fileslots_clearFileSlot( $slot, $objectID, ZBS_TYPE_CONTACT ); } + } + } - } #} else w/e + if ( $changeFlag ) { + zeroBSCRM_files_updateFiles( $fileType, $objectID, $ret ); + } + } #} else w/e - #} Then delete actual file ... - if ($changeFlag && isset($fileObjToDelete) && isset($fileObjToDelete['file'])){ + #} Then delete actual file ... + if ( $changeFlag && isset( $fileObjToDelete ) && isset( $fileObjToDelete['file'] ) ) { - #} Brutal - #} #recyclingbin - if (file_exists($fileObjToDelete['file'])) { + #} Brutal + #} #recyclingbin + if ( file_exists( $fileObjToDelete['file'] ) ) { - #} Delete - unlink($fileObjToDelete['file']); + #} Delete + unlink( $fileObjToDelete['file'] ); - #} Check if deleted: - if (file_exists($fileObjToDelete['file'])){ + #} Check if deleted: + if ( file_exists( $fileObjToDelete['file'] ) ) { - // try and be more forceful: - chmod($fileObjToDelete['file'], 0777); - unlink(realpath($fileObjToDelete['file'])); + // try and be more forceful: + chmod( $fileObjToDelete['file'], 0777 ); + unlink( realpath( $fileObjToDelete['file'] ) ); - if (file_exists($fileObjToDelete['file'])){ - - // tone down perms, at least - chmod($fileObjToDelete['file'], 0644); + if ( file_exists( $fileObjToDelete['file'] ) ) { - // add message - return __('Could not delete file from server:','zero-bs-crm').' '.$fileObjToDelete['file']; + // tone down perms, at least + chmod( $fileObjToDelete['file'], 0644 ); - } + // add message + return __( 'Could not delete file from server:', 'zero-bs-crm' ) . ' ' . $fileObjToDelete['file']; } - } - } - - return true; - } + return true; } + } + } #} / can manage options - } #} / can manage options - - - return false; - } - - + return false; +} -/* ====================================================== - File Upload related funcs - ====================================================== */ +/* +====================================================== + File Upload related funcs + ====================================================== */ - function zeroBSCRM_privatiseUploadedFile($fromPath='',$filename=''){ +function zeroBSCRM_privatiseUploadedFile( $fromPath = '', $filename = '' ) { - #} Check dir created - $currentUploadDirObj = zeroBSCRM_privatisedDirCheck(); - if (is_array($currentUploadDirObj) && isset($currentUploadDirObj['path'])){ + #} Check dir created + $currentUploadDirObj = zeroBSCRM_privatisedDirCheck(); + if ( is_array( $currentUploadDirObj ) && isset( $currentUploadDirObj['path'] ) ) { $currentUploadDir = $currentUploadDirObj['path']; $currentUploadURL = $currentUploadDirObj['url']; - } else { - $currentUploadDir = false; - $currentUploadURL = false; - } - - if (!empty($currentUploadDir)){ - - // generate a safe name + check no file existing - // this is TEMP code to be rewritten on formally secure file sys WH - $filePreHash = md5($filename.time()); - // actually limit to first 16 chars is plenty - $filePreHash = substr($filePreHash,0,16); - $finalFileName = $filePreHash.'-'.$filename; - $finalFilePath = $currentUploadDir.'/'.$finalFileName; - - // check exists, deal with (unlikely) dupe names - $c = 1; - while (file_exists($finalFilePath) && $c < 50){ - - // remake - $finalFileName = $filePreHash.'-'.$c.'-'.$filename; - $finalFilePath = $currentUploadDir.'/'.$finalFileName; - - // let it roll + retest - $c++; - } + } else { + $currentUploadDir = false; + $currentUploadURL = false; + } - if (rename($fromPath.'/'.$filename,$finalFilePath)){ + if ( ! empty( $currentUploadDir ) ) { - // moved :) + // generate a safe name + check no file existing + // this is TEMP code to be rewritten on formally secure file sys WH + $filePreHash = md5( $filename . time() ); + // actually limit to first 16 chars is plenty + $filePreHash = substr( $filePreHash, 0, 16 ); + $finalFileName = $filePreHash . '-' . $filename; + $finalFilePath = $currentUploadDir . '/' . $finalFileName; - // check perms? - /* https://developer.wordpress.org/reference/functions/wp_upload_bits/ - // Set correct file permissions - $stat = @ stat( dirname( $new_file ) ); - $perms = $stat['mode'] & 0007777; - $perms = $perms & 0000666; - @ chmod( $new_file, $perms ); - */ + // check exists, deal with (unlikely) dupe names + $c = 1; + while ( file_exists( $finalFilePath ) && $c < 50 ) { - $endPath = $finalFilePath; - // this url is temp, it should be fed via php later. - $endURL = $currentUploadURL.'/'.$finalFileName; + // remake + $finalFileName = $filePreHash . '-' . $c . '-' . $filename; + $finalFilePath = $currentUploadDir . '/' . $finalFileName; + // let it roll + retest + ++$c; + } - // the caller-func needs to remove/change data/meta :) - return array('file'=>$endPath,'url'=>$endURL); + if ( rename( $fromPath . '/' . $filename, $finalFilePath ) ) { - } else { + // moved :) - // failed to move - return false; - } + // check perms? + /* + https://developer.wordpress.org/reference/functions/wp_upload_bits/ + // Set correct file permissions + $stat = @ stat( dirname( $new_file ) ); + $perms = $stat['mode'] & 0007777; + $perms = $perms & 0000666; + @ chmod( $new_file, $perms ); + */ + $endPath = $finalFilePath; + // this url is temp, it should be fed via php later. + $endURL = $currentUploadURL . '/' . $finalFileName; - } + // the caller-func needs to remove/change data/meta :) + return array( + 'file' => $endPath, + 'url' => $endURL, + ); - return false; // couldn't - no dir to move to :) + } else { + // failed to move + return false; + } + } - } + return false; // couldn't - no dir to move to :) +} function zeroBSCRM_privatisedDirCheck( $echo = false ) { $storage_dir_info = jpcrm_storage_dir_info(); @@ -426,22 +417,25 @@ function jpcrm_get_hash_for_object( $object_id, $object_hash_string ) { /* * Returns the 'dir info' for the storage folder. - * dir info = - * [ + * dir info = + * [ * 'path' => 'path for the physical file', * 'url' => 'public facing url' * ] * */ function jpcrm_storage_dir_info() { - $uploads_dir = WP_CONTENT_DIR; - $uploads_url = content_url(); + $uploads_dir = WP_CONTENT_DIR; + $uploads_url = content_url(); $private_dir_name = 'jpcrm-storage'; if ( ! empty( $uploads_dir ) && ! empty( $uploads_url ) ) { $full_dir_path = $uploads_dir . '/' . $private_dir_name; $full_url = $uploads_url . '/' . $private_dir_name; - return array( 'path' => $full_dir_path, 'url' => $full_url ); + return array( + 'path' => $full_dir_path, + 'url' => $full_url, + ); } return false; @@ -468,14 +462,14 @@ function wf_jpcrm_storage_dir_path() { function jpcrm_storage_fonts_dir_path() { $root_storage_info = jpcrm_storage_dir_info(); - if ( !$root_storage_info ) { + if ( ! $root_storage_info ) { return false; } $fonts_dir = $root_storage_info['path'] . '/fonts/'; // Create and secure fonts dir as needed - if ( !jpcrm_create_and_secure_dir_from_external_access( $fonts_dir ) || !is_dir( $fonts_dir ) ) { + if ( ! jpcrm_create_and_secure_dir_from_external_access( $fonts_dir ) || ! is_dir( $fonts_dir ) ) { return false; } @@ -484,18 +478,18 @@ function jpcrm_storage_fonts_dir_path() { /* * Returns the 'dir info' for the provided generic object. This directory should - * be used to store all files associated to this object (e.g. contact files, - * company files, invoices...). - * - * dir info = - * [ - * 'subfolder_1' => - * [ + * be used to store all files associated to this object (e.g. contact files, + * company files, invoices...). + * + * dir info = + * [ + * 'subfolder_1' => + * [ * 'path' => 'path for the physical file', * 'url' => 'public facing url' * ], - * 'subfolder_2' => - * [ + * 'subfolder_2' => + * [ * 'path' => 'path for the physical file', * 'url' => 'public facing url' * ], @@ -514,9 +508,9 @@ function jpcrm_storage_dir_info_for_object( $object_id, $object_hash_string, $ob return false; } - $parent_storage_info = array( - 'path' => $root_storage_info['path'] . '/' . $object_parent_folder, - 'url' => $root_storage_info['url'] . '/' . $object_parent_folder + $parent_storage_info = array( + 'path' => $root_storage_info['path'] . '/' . $object_parent_folder, + 'url' => $root_storage_info['url'] . '/' . $object_parent_folder, ); if ( ! jpcrm_create_and_secure_dir_from_external_access( $parent_storage_info['path'], false ) ) { @@ -536,7 +530,7 @@ function jpcrm_storage_dir_info_for_object( $object_id, $object_hash_string, $ob foreach ( $subfolder_list as $subfolder ) { $object_dir_info[ $subfolder ] = array( 'path' => $parent_full_path . $subfolder, - 'url' => $parent_storage_info['url'] . $parent_relative_path . $subfolder, + 'url' => $parent_storage_info['url'] . $parent_relative_path . $subfolder, ); } @@ -551,13 +545,12 @@ function jpcrm_storage_dir_info_for_object( $object_id, $object_hash_string, $ob */ function jpcrm_storage_dir_info_for_contact( $contact_id ) { - return jpcrm_storage_dir_info_for_object( + return jpcrm_storage_dir_info_for_object( $contact_id, 'contact_hash', 'contacts', array( 'avatar', 'files' ) ); - } /* @@ -567,13 +560,12 @@ function jpcrm_storage_dir_info_for_contact( $contact_id ) { */ function jpcrm_storage_dir_info_for_company( $company_id ) { - return jpcrm_storage_dir_info_for_object( + return jpcrm_storage_dir_info_for_object( $company_id, 'company_hash', 'companies', array( 'files' ) ); - } /* @@ -583,13 +575,12 @@ function jpcrm_storage_dir_info_for_company( $company_id ) { */ function jpcrm_storage_dir_info_for_invoices( $invoice_id ) { - return jpcrm_storage_dir_info_for_object( + return jpcrm_storage_dir_info_for_object( $invoice_id, 'invoice_hash', 'invoices', array( 'files' ) ); - } /* @@ -599,25 +590,24 @@ function jpcrm_storage_dir_info_for_invoices( $invoice_id ) { */ function jpcrm_storage_dir_info_for_quotes( $quote_id ) { - return jpcrm_storage_dir_info_for_object( + return jpcrm_storage_dir_info_for_object( $quote_id, 'quote_hash', 'quotes', array( 'files' ) ); - } /* * Saves a file uploaded by an admin from $_FILES[ $param_name ] to the folder * $target_dir_info['path'] and returns an array( 'error' => something ) in the - * case of errors and an + * case of errors and an * array( 'file' => file_path, 'url' => file_url, 'priv' => boolean) in the case * of success. */ function jpcrm_save_admin_upload_to_folder( $param_name, $target_dir_info ) { $upload = wp_upload_bits( $_FILES[ $param_name ]['name'], null, file_get_contents( $_FILES[ $param_name ]['tmp_name'] ) ); - if( isset( $upload['error'] ) && $upload['error'] != 0 ) { + if ( isset( $upload['error'] ) && $upload['error'] != 0 ) { return $upload; } // change this to return a custom error in the future if needed @@ -631,11 +621,13 @@ function jpcrm_save_admin_upload_to_folder( $param_name, $target_dir_info ) { $upload_path = $target_dir_info['path']; $upload_folder_exists = jpcrm_create_and_secure_dir_from_external_access( $upload_path, false ); if ( $upload_folder_exists ) { - $upload_filename = sanitize_file_name( sprintf( - '%s-%s', - $zbs->encryption->get_rand_hex( 16 ), - $_FILES[ $param_name ]['name'] // for admins we are accepting "filename.ext" as provided by $_FILES - ) ); + $upload_filename = sanitize_file_name( + sprintf( + '%s-%s', + $zbs->encryption->get_rand_hex( 16 ), + $_FILES[ $param_name ]['name'] // for admins we are accepting "filename.ext" as provided by $_FILES + ) + ); if ( move_uploaded_file( $_FILES[ $param_name ]['tmp_name'], $upload_path . '/' . $upload_filename ) ) { $upload['file'] = $upload_path . '/' . $upload_filename; @@ -650,8 +642,8 @@ function jpcrm_save_admin_upload_to_folder( $param_name, $target_dir_info ) { // 2.95.5+ we also add a subdir for 'work' (this is used by CPP when making thumbs, for example) function zeroBSCRM_privatisedDirCheckWorks( $echo = false ) { - $uploads_dir = WP_CONTENT_DIR; - $uploads_url = content_url(); + $uploads_dir = WP_CONTENT_DIR; + $uploads_url = content_url(); $private_dir_name = 'jpcrm-storage/tmp'; if ( ! empty( $uploads_dir ) && ! empty( $uploads_url ) ) { @@ -659,7 +651,7 @@ function zeroBSCRM_privatisedDirCheckWorks( $echo = false ) { $full_url = $uploads_url . '/' . $private_dir_name; // check existence - if ( !file_exists( $full_dir_path ) ) { + if ( ! file_exists( $full_dir_path ) ) { // doesn't exist, attempt to create mkdir( $full_dir_path, 0755, true ); @@ -670,251 +662,255 @@ function zeroBSCRM_privatisedDirCheckWorks( $echo = false ) { if ( is_dir( $full_dir_path ) ) { jpcrm_create_and_secure_dir_from_external_access( $full_dir_path ); - return array( 'path' => $full_dir_path, 'url' => $full_url ); + return array( + 'path' => $full_dir_path, + 'url' => $full_url, + ); } } return false; } -/* ====================================================== - / File Upload related funcs - ====================================================== */ - -/* ====================================================== - File Slots helpers - ====================================================== */ - - function zeroBSCRM_fileSlots_getFileSlots($objType=1){ - - global $zbs; - - $fileSlots = array(); +/* +====================================================== + / File Upload related funcs + ====================================================== */ - $settings = zeroBSCRM_getSetting('customfields'); $cfbInd = 1; +/* +====================================================== + File Slots helpers + ====================================================== */ - switch ($objType){ +function zeroBSCRM_fileSlots_getFileSlots( $objType = 1 ) { - case 1: + global $zbs; - if (isset($settings['customersfiles']) && is_array($settings['customersfiles']) && count($settings['customersfiles']) > 0){ + $fileSlots = array(); - foreach ($settings['customersfiles'] as $cfb){ + $settings = zeroBSCRM_getSetting( 'customfields' ); + $cfbInd = 1; - $cfbName = ''; if (isset($cfb[0])) $cfbName = $cfb[0]; - $key = $zbs->DAL->makeSlug($cfbName); // $cfbInd - if (!empty($key)){ - $fileSlots[] = array('key'=>$key,'name'=>$cfbName); - $cfbInd++; - } + switch ( $objType ) { - } + case 1: + if ( isset( $settings['customersfiles'] ) && is_array( $settings['customersfiles'] ) && count( $settings['customersfiles'] ) > 0 ) { - } + foreach ( $settings['customersfiles'] as $cfb ) { - break; + $cfbName = ''; + if ( isset( $cfb[0] ) ) { + $cfbName = $cfb[0]; + } + $key = $zbs->DAL->makeSlug( $cfbName ); // $cfbInd + if ( ! empty( $key ) ) { + $fileSlots[] = array( + 'key' => $key, + 'name' => $cfbName, + ); + ++$cfbInd; + } + } + } - } + break; - return $fileSlots; - } + } - // returns the slot (if assigned) of a given file - function zeroBSCRM_fileslots_fileSlot($file='',$objID=-1,$objType=1){ + return $fileSlots; +} - // get all slotted files for contact/obj - - if ($objID > 0 && !empty($file)){ + // returns the slot (if assigned) of a given file +function zeroBSCRM_fileslots_fileSlot( $file = '', $objID = -1, $objType = 1 ) { - global $zbs; - $fileSlots = zeroBSCRM_fileslots_allSlots($objID,$objType); - // cycle through - if (count($fileSlots) > 0){ + // get all slotted files for contact/obj - foreach ($fileSlots as $fsKey => $fsFile){ + if ( $objID > 0 && ! empty( $file ) ) { - if ($fsFile == $file) return $fsKey; + global $zbs; + $fileSlots = zeroBSCRM_fileslots_allSlots( $objID, $objType ); + // cycle through + if ( count( $fileSlots ) > 0 ) { - } + foreach ( $fileSlots as $fsKey => $fsFile ) { - } + if ( $fsFile == $file ) { + return $fsKey; + } + } + } + } + return false; +} + // returns all slots (if assigned) of a given obj(contact) +function zeroBSCRM_fileslots_allSlots( $objID = -1, $objType = 1 ) { - } - return false; - } + if ( $objID > 0 ) { + global $zbs; + $fileSlots = zeroBSCRM_fileSlots_getFileSlots( ZBS_TYPE_CONTACT ); + $ret = array(); + if ( count( $fileSlots ) > 0 ) { - // returns all slots (if assigned) of a given obj(contact) - function zeroBSCRM_fileslots_allSlots($objID=-1,$objType=1){ + foreach ( $fileSlots as $fs ) { - if ($objID > 0){ + $ret[ $fs['key'] ] = zeroBSCRM_fileslots_fileInSlot( $fs['key'], $objID, $objType ); - global $zbs; - $fileSlots = zeroBSCRM_fileSlots_getFileSlots(ZBS_TYPE_CONTACT); - $ret = array(); - if (count($fileSlots) > 0){ + } + } + return $ret; - foreach ($fileSlots as $fs){ + } + return false; +} - $ret[$fs['key']] = zeroBSCRM_fileslots_fileInSlot($fs['key'],$objID,$objType); + // returns a file for a slot +function zeroBSCRM_fileslots_fileInSlot( $fileSlot = '', $objID = -1, $objType = 1 ) { - } + if ( $objID > 0 ) { - } - return $ret; - - } - return false; - } + global $zbs; - // returns a file for a slot - function zeroBSCRM_fileslots_fileInSlot($fileSlot='',$objID=-1,$objType=1){ + return $zbs->DAL->meta( $objType, $objID, 'cfile_' . $fileSlot ); - if ($objID > 0){ + } + return false; +} - global $zbs; + // adds a file to a slot +function zeroBSCRM_fileslots_addToSlot( $fileSlot = '', $file = '', $objID = -1, $objType = 1, $overrite = false ) { - return $zbs->DAL->meta($objType,$objID,'cfile_'.$fileSlot); + if ( $objID > 0 ) { - } - return false; - - } + // echo '
zeroBSCRM_fileslots_addToSlot '.$fileSlot.' '.$file.' '.$objID.' ext:'.zeroBSCRM_fileslots_fileInSlot($fileSlot,$objID).'!'; - // adds a file to a slot - function zeroBSCRM_fileslots_addToSlot($fileSlot='',$file='',$objID=-1,$objType=1,$overrite=false){ + global $zbs; - if ($objID > 0){ + // check existing? + if ( ! $overrite ) { + $existingFile = zeroBSCRM_fileslots_fileInSlot( $fileSlot, $objID ); + if ( ! empty( $existingFile ) ) { + return false; + } + } else { - //echo '
zeroBSCRM_fileslots_addToSlot '.$fileSlot.' '.$file.' '.$objID.' ext:'.zeroBSCRM_fileslots_fileInSlot($fileSlot,$objID).'!'; + // overrite... so remove any if present before.. + zeroBSCRM_fileslots_clearFileSlot( $fileSlot, $objID, $objType ); + } - global $zbs; + // DAL2 add via meta (for now) + $zbs->DAL->updateMeta( $objType, $objID, 'cfile_' . $fileSlot, $file ); + return true; - // check existing? - if (!$overrite){ - $existingFile = zeroBSCRM_fileslots_fileInSlot($fileSlot,$objID); - if (!empty($existingFile)) return false; - } else { + } - // overrite... so remove any if present before.. - zeroBSCRM_fileslots_clearFileSlot($fileSlot,$objID,$objType); - } + return false; +} - // DAL2 add via meta (for now) - $zbs->DAL->updateMeta($objType,$objID,'cfile_'.$fileSlot,$file); - return true; +function zeroBSCRM_fileslots_clearFileSlot( $fileSlot = '', $objID = -1, $objType = 1 ) { - } + if ( $objID > 0 ) { - return false; + global $zbs; + return $zbs->DAL->deleteMeta( + array( + 'objtype' => $objType, + 'objid' => $objID, + 'key' => 'cfile_' . $fileSlot, + ) + ); - - } + } - function zeroBSCRM_fileslots_clearFileSlot($fileSlot='',$objID=-1,$objType=1){ + return false; +} - if ($objID > 0){ +function zeroBSCRM_files_baseName( $filePath = '', $privateRepo = false ) { - global $zbs; - return $zbs->DAL->deleteMeta(array( - 'objtype' => $objType, - 'objid' => $objID, - 'key' => 'cfile_'.$fileSlot - )); + $file = ''; + if ( ! empty( $filePath ) ) { + $file = basename( $filePath ); + if ( $privateRepo ) { + $file = substr( $file, strpos( $file, '-' ) + 1 ); } + } - return false; - } - - - function zeroBSCRM_files_baseName($filePath='',$privateRepo=false){ - - $file = ''; - if (!empty($filePath)){ - - - $file = basename($filePath); - if ($privateRepo) $file = substr($file,strpos($file, '-')+1); - - } - - return $file; - - } + return $file; +} -/* ====================================================== - / File Slots helpers - ====================================================== */ +/* +====================================================== + / File Slots helpers + ====================================================== */ // gives an hashed filename+salt that is generally suitable for filesystems -function jpcrm_get_hashed_filename( $filename, $suffix='' ) { +function jpcrm_get_hashed_filename( $filename, $suffix = '' ) { global $zbs; $zbs->load_encryption(); - $salt = $zbs->encryption->get_encryption_key( 'filename' ); + $salt = $zbs->encryption->get_encryption_key( 'filename' ); $hashed_filename = $zbs->encryption->hash( $filename . $salt ) . $suffix; return $hashed_filename; } - /** - * Checks legitimacy (in so far as practicable) of an uploaded file + * Checks legitimacy (in so far as practicable) of an uploaded file * With default 'setting' params, checks against the core functions: * `zeroBS_acceptableFileTypeMIMEArr()` and `zeroBS_acceptableFileTypeListArr()` * (Which reflect the core setting) - * + * * @param $FILE * @param $check_file_extension string|array - if string, can be single, e.g. `.pdf`, if array, can be multiple strings * @param $check_mime_type string|array - if string, can be single, e.g. `application/pdf`, if array, can be multiple strings */ -function jpcrm_file_check_mime_extension( $FILE, $check_file_extension = 'setting', $check_mime_type = 'setting' ){ +function jpcrm_file_check_mime_extension( $FILE, $check_file_extension = 'setting', $check_mime_type = 'setting' ) { // expects $_FILES type array (e.g. pass $_FILES['zbsc_file_attachment']) - if ( !is_array( $FILE ) || !isset( $FILE['name'] ) || !isset( $FILE['type'] ) || !isset( $FILE['tmp_name'] ) ){ - return false; - } + if ( ! is_array( $FILE ) || ! isset( $FILE['name'] ) || ! isset( $FILE['type'] ) || ! isset( $FILE['tmp_name'] ) ) { + return false; + } // check file extension // retrieve settings, or prepare an array of acceptable file extensions from passed string/array - if ( $check_file_extension == 'setting' ){ - $check_file_extension = zeroBS_acceptableFileTypeListArr(); - } elseif ( $check_file_extension != 'setting' && !is_array( $check_file_extension ) ){ - $check_file_extension = array( $check_file_extension ); - } + if ( $check_file_extension == 'setting' ) { + $check_file_extension = zeroBS_acceptableFileTypeListArr(); + } elseif ( $check_file_extension != 'setting' && ! is_array( $check_file_extension ) ) { + $check_file_extension = array( $check_file_extension ); + } // check actual extension - if ( !in_array( '.' . pathinfo( $FILE['name'], PATHINFO_EXTENSION ), $check_file_extension ) ){ - return false; - } + if ( ! in_array( '.' . pathinfo( $FILE['name'], PATHINFO_EXTENSION ), $check_file_extension ) ) { + return false; + } // check mime // retrieve settings, or prepare an array of acceptable file extensions from passed string/array - if ( $check_mime_type == 'setting' ){ - $check_mime_type = zeroBS_acceptableFileTypeMIMEArr(); - } elseif ( $check_mime_type != 'setting' && !is_array( $check_mime_type ) ){ - $check_mime_type = array( $check_mime_type ); - } + if ( $check_mime_type == 'setting' ) { + $check_mime_type = zeroBS_acceptableFileTypeMIMEArr(); + } elseif ( $check_mime_type != 'setting' && ! is_array( $check_mime_type ) ) { + $check_mime_type = array( $check_mime_type ); + } // catch 'all' legacy solution which (perhaps dangerously) sidesteps this check // will do mime check if legacy 'all' is empty, which includes false, 0, and !isset() - if ( empty( $check_mime_type['all'] ) ) { - // check actual mime type - if ( ! in_array( $FILE['type'], $check_mime_type ) ) { - return false; - } + if ( empty( $check_mime_type['all'] ) ) { + // check actual mime type + if ( ! in_array( $FILE['type'], $check_mime_type ) ) { + return false; + } - // also check the mime type directly inferred from the uploaded file - // note: we don't check this type against $FILE['type'] because it - // doesn't really matter if they are different but both accepted types - $tmp_file_type = jpcrm_get_mimetype( $FILE['tmp_name'] ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // also check the mime type directly inferred from the uploaded file + // note: we don't check this type against $FILE['type'] because it + // doesn't really matter if they are different but both accepted types + $tmp_file_type = jpcrm_get_mimetype( $FILE['tmp_name'] ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ( ! in_array( $tmp_file_type, $check_mime_type ) ) { - return false; - } + if ( ! in_array( $tmp_file_type, $check_mime_type ) ) { + return false; } + } return true; } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.FormatHelpers.php b/projects/plugins/crm/includes/ZeroBSCRM.FormatHelpers.php index 3643eafabbf9..9c20c7e86484 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.FormatHelpers.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.FormatHelpers.php @@ -1,5 +1,6 @@ - 0 ){ - - $c = '' . sprintf( __('Contact since %s',"zero-bs-crm"), $contact['created_date'] ); + if ( $contact['created'] > 0 ) { + + $c = '' . sprintf( __( 'Contact since %s', 'zero-bs-crm' ), $contact['created_date'] ); } - // in co? + check if B2B mode active - $b2bMode = zeroBSCRM_getSetting('companylevelcustomers'); - if ( $b2bMode == 1 ){ - $possibleCo = zeroBS_getCustomerCompanyID($contact['id']); - if (!empty($possibleCo) && $possibleCo > 0){ + // in co? + check if B2B mode active + $b2bMode = zeroBSCRM_getSetting( 'companylevelcustomers' ); + if ( $b2bMode == 1 ) { + $possibleCo = zeroBS_getCustomerCompanyID( $contact['id'] ); + if ( ! empty( $possibleCo ) && $possibleCo > 0 ) { - $co = zeroBS_getCompany($possibleCo); + $co = zeroBS_getCompany( $possibleCo ); - if (is_array($co) && isset($co['name']) && !empty($co['name'])){ + if ( is_array( $co ) && isset( $co['name'] ) && ! empty( $co['name'] ) ) { - $c .= '
' . __('Works for',"zero-bs-crm").' '.$co['name'].''; - } - } - } - - #} New 2.98+ - $contact_location = ""; - if(!empty($contact['county']) && !empty($contact['country'])){ - $contact_location = $contact['county'] . ", " . $contact['country']; - }else if(!empty($contact['county']) && empty($contact['country'])){ - $contact_location = $contact['county']; - }else if(empty($contact['county']) && !empty($contact['country'])){ - $contact_location = $contact['country']; + $c .= '
' . __( 'Works for', 'zero-bs-crm' ) . ' ' . $co['name'] . ''; + } } + } - if($contact_location != ""){ - $c .= '
' . $contact_location; - } + #} New 2.98+ + $contact_location = ''; + if ( ! empty( $contact['county'] ) && ! empty( $contact['country'] ) ) { + $contact_location = $contact['county'] . ', ' . $contact['country']; + } elseif ( ! empty( $contact['county'] ) && empty( $contact['country'] ) ) { + $contact_location = $contact['county']; + } elseif ( empty( $contact['county'] ) && ! empty( $contact['country'] ) ) { + $contact_location = $contact['country']; + } - //tags for easier viewing UI wise (2.98+) + if ( $contact_location != '' ) { + $c .= '
' . $contact_location; + } - $customerTags = zeroBSCRM_getCustomerTagsByID($contact['id']); - if (!is_array($customerTags)) $customerTags = array(); - if (count($customerTags) > 0){ - $c .= '
' . zeroBSCRM_html_linkedContactTags($contact['id'],$customerTags,'ui tag label zbs-mini-tag', false, true); - } + // tags for easier viewing UI wise (2.98+) + $customerTags = zeroBSCRM_getCustomerTagsByID( $contact['id'] ); + if ( ! is_array( $customerTags ) ) { + $customerTags = array(); + } + if ( count( $customerTags ) > 0 ) { + $c .= '
' . zeroBSCRM_html_linkedContactTags( $contact['id'], $customerTags, 'ui tag label zbs-mini-tag', false, true ); + } - // assigned to? - $usingOwnership = zeroBSCRM_getSetting('perusercustomers'); - if ($usingOwnership){ - $possibleOwner = zeroBS_getOwner($contact['id'],true,'zerobs_customer'); - if (is_array($possibleOwner) && isset($possibleOwner['ID']) && !empty($possibleOwner['ID'])){ + // assigned to? + $usingOwnership = zeroBSCRM_getSetting( 'perusercustomers' ); + if ( $usingOwnership ) { + $possibleOwner = zeroBS_getOwner( $contact['id'], true, 'zerobs_customer' ); + if ( is_array( $possibleOwner ) && isset( $possibleOwner['ID'] ) && ! empty( $possibleOwner['ID'] ) ) { - if (isset($possibleOwner['OBJ']) && isset($possibleOwner['OBJ']->user_nicename)){ - $user_avatar = jpcrm_get_avatar( $possibleOwner['OBJ']->ID, 25 ); - $c .= '
' . __('Assigned to: ',"zero-bs-crm").' '. $user_avatar . ' ' . $possibleOwner['OBJ']->display_name . '
'; - } - } + if ( isset( $possibleOwner['OBJ'] ) && isset( $possibleOwner['OBJ']->user_nicename ) ) { + $user_avatar = jpcrm_get_avatar( $possibleOwner['OBJ']->ID, 25 ); + $c .= '
' . __( 'Assigned to: ', 'zero-bs-crm' ) . ' ' . $user_avatar . ' ' . $possibleOwner['OBJ']->display_name . '
'; + } + } } - $c = apply_filters('zerobscrm_contactintro_filter', $c, $contact['id']); - - return $c; + $c = apply_filters( 'zerobscrm_contactintro_filter', $c, $contact['id'] ); + return $c; } -function zeroBSCRM_html_contactSince($customer){ - echo " "; - esc_html_e("Contact since ", "zero-bs-crm"); - $d = new DateTime($customer['created']); - $formatted_date = $d->format(zeroBSCRM_getDateFormat()); - return "" . $formatted_date . ""; +function zeroBSCRM_html_contactSince( $customer ) { + echo " "; + esc_html_e( 'Contact since ', 'zero-bs-crm' ); + $d = new DateTime( $customer['created'] ); + $formatted_date = $d->format( zeroBSCRM_getDateFormat() ); + return "" . $formatted_date . ''; } - -function zeroBSCRM_html_sendemailto($prefillID=-1,$emailAddress='',$withIco=true){ - global $zbs; - if ($prefillID > 0 && !empty($emailAddress)){ - if ($withIco) echo " "; - echo ""; - echo esc_html( $emailAddress ); - echo ""; +function zeroBSCRM_html_sendemailto( $prefillID = -1, $emailAddress = '', $withIco = true ) { + global $zbs; + if ( $prefillID > 0 && ! empty( $emailAddress ) ) { + if ( $withIco ) { + echo " "; + } + echo ""; + echo esc_html( $emailAddress ); + echo ''; } } +// added echo = true (i.e by default echo this, but need to return it in some cases) +function zeroBSCRM_html_linkedContactTags( $contactID = -1, $tags = false, $classStr = '', $echo = true, $trim = false, $limit = false ) { -//added echo = true (i.e by default echo this, but need to return it in some cases) -function zeroBSCRM_html_linkedContactTags($contactID=-1,$tags=false,$classStr='',$echo = true, $trim = false, $limit = false){ - - global $zbs; + global $zbs; $res = ''; - //check if we have a way to pass a LIMIT to the below (cos tons of tags in the top box is bad) + // check if we have a way to pass a LIMIT to the below (cos tons of tags in the top box is bad) - if ($contactID > 0 && $tags == false) $tags = zeroBSCRM_getCustomerTagsByID($contactID); - - if (count($tags) > 0) - foreach ($tags as $tag){ + if ( $contactID > 0 && $tags == false ) { + $tags = zeroBSCRM_getCustomerTagsByID( $contactID ); + } - // DAL1/2 switch - $tagName = ''; $tagID = -1; - if (is_array($tag)){ - $tagName = $tag['name']; - $tagID = $tag['id']; - } else { - $tagName = $tag->name; - $tagID = $tag->term_id; - } - - $short_tag_name = $trim && strlen($tagName) > 50 ? substr($tagName,0,10)."..." : $tagName; + if ( count( $tags ) > 0 ) { + foreach ( $tags as $tag ) { - $link = admin_url('admin.php?page='.$zbs->slugs['managecontacts'].'&zbs_tag='.$tagID); - $res .= '' . esc_html( $short_tag_name ) . ''; - - + // DAL1/2 switch + $tagName = ''; + $tagID = -1; + if ( is_array( $tag ) ) { + $tagName = $tag['name']; + $tagID = $tag['id']; + } else { + $tagName = $tag->name; + $tagID = $tag->term_id; + } + + $short_tag_name = $trim && strlen( $tagName ) > 50 ? substr( $tagName, 0, 10 ) . '...' : $tagName; + + $link = admin_url( 'admin.php?page=' . $zbs->slugs['managecontacts'] . '&zbs_tag=' . $tagID ); + $res .= '' . esc_html( $short_tag_name ) . ''; + + } } - - if ($echo) + + if ( $echo ) { echo $res; - else + } else { return $res; - - + } } - // builds the HTML for companies linked to a contact // note can pass $companiesArray parameter optionally to avoid the need to retrieve companies (DAL3+ these are got with the getContact) -function zeroBSCRM_html_linkedContactCompanies($contactID=-1,$companiesArray=false){ +function zeroBSCRM_html_linkedContactCompanies( $contactID = -1, $companiesArray = false ) { global $zbs; - #} Contacts' companies - if (!is_array($companiesArray)) - $companies = $zbs->DAL->contacts->getContactCompanies($contactID); - else - $companies = $companiesArray; - - $companiesStr = ''; + #} Contacts' companies + if ( ! is_array( $companiesArray ) ) { + $companies = $zbs->DAL->contacts->getContactCompanies( $contactID ); + } else { + $companies = $companiesArray; + } - foreach ($companies as $company){ + $companiesStr = ''; - if (is_array($company) && isset($company['name']) && !empty($company['name'])){ + foreach ( $companies as $company ) { - $companiesStr .= ''.$company['name'].''; + if ( is_array( $company ) && isset( $company['name'] ) && ! empty( $company['name'] ) ) { - } - } + $companiesStr .= '' . $company['name'] . ''; - return $companiesStr; + } + } + return $companiesStr; } -function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=false){ +function zeroBSCRM_html_contactTimeline( $contactID = -1, $logs = false, $contactObj = false ) { global $zeroBSCRM_logTypes, $zbs; - if (isset($contactID) && $contactID > 0 && $logs === false){ + if ( isset( $contactID ) && $contactID > 0 && $logs === false ) { // get logs - $logs = zeroBSCRM_getContactLogs($contactID,true,100,0,'',false); + $logs = zeroBSCRM_getContactLogs( $contactID, true, 100, 0, '', false ); } @@ -187,89 +186,94 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa // - if over 10, show creation, and 'higher level' logs, then latest // - 7/2/19 WH modified this to catch "creation" logs properly, and always put them at the end // ... (we were getting instances where transaction + contact created in same second, which caused the order to be off) - $logsToShow = array(); $creationLog = false; + $logsToShow = array(); + $creationLog = false; - if (count($logs) <= 10){ + if ( count( $logs ) <= 10 ) { $logsToShow = $logs; - $logsF = array(); $creationLog = false; - // here we have to just do a re-order to make sure created is last :) - foreach ($logsToShow as $l){ + $logsF = array(); + $creationLog = false; + // here we have to just do a re-order to make sure created is last :) + foreach ( $logsToShow as $l ) { - if ($l['type'] == 'created') + if ( $l['type'] == 'created' ) { $creationLog = $l; - else + } else { $logsF[] = $l; - + } } // add it - if (is_array($creationLog)) $logsF[] = $creationLog; + if ( is_array( $creationLog ) ) { + $logsF[] = $creationLog; + } // tidy - $logsToShow = $logsF; - unset($logsF); - unset($creationLog); - + $logsToShow = $logsF; + unset( $logsF ); + unset( $creationLog ); } else { // cherry pick 9 logs // 1) latest - $logsToShow[] = current($logs); + $logsToShow[] = current( $logs ); // 2) cherry pick 8 middle events - $logTypesToPrioritise = array( 'Quote: Accepted', - 'Quote: Refused', - 'Invoice: Sent', - 'Invoice: Part Paid', - 'Invoice: Paid', - 'Invoice: Refunded', - 'Transaction', - 'Feedback', - 'Status Change', - 'Client Portal User Created', - 'Call', - 'Email', - 'Note' - ); + $logTypesToPrioritise = array( + 'Quote: Accepted', + 'Quote: Refused', + 'Invoice: Sent', + 'Invoice: Part Paid', + 'Invoice: Paid', + 'Invoice: Refunded', + 'Transaction', + 'Feedback', + 'Status Change', + 'Client Portal User Created', + 'Call', + 'Email', + 'Note', + ); // convert to type stored in db $x = array(); foreach ( $logTypesToPrioritise as $lt ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $x[] = $zbs->DAL->logs->logTypeIn( $lt ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase } - $logTypesToPrioritise = $x; unset($x); + $logTypesToPrioritise = $x; + unset( $x ); // for now, abbreviated, just cycle through + pick any in prioritised group... could do this staggered by type/time later - //skip first item, as we've already added it earlier - foreach (array_slice($logs,1) as $l){ - if ($l['type'] == 'created'){ + // skip first item, as we've already added it earlier + foreach ( array_slice( $logs, 1 ) as $l ) { + if ( $l['type'] == 'created' ) { - // add to this var - $creationLog = $l; + // add to this var + $creationLog = $l; - } else { + } else { - // normal pickery - if (count($logsToShow) < 9){ - if (in_array($l['type'], $logTypesToPrioritise)) $logsToShow[] = $l; - } else { - break; + // normal pickery + if ( count( $logsToShow ) < 9 ) { + if ( in_array( $l['type'], $logTypesToPrioritise ) ) { + $logsToShow[] = $l; } - + } else { + break; } - } + } // 3) created // for now, assume first log is created, if it's not, add one with date // ... this'll cover 100+ logs situ - // WH changed 7/2/18 to remove issue mentioned above + // WH changed 7/2/18 to remove issue mentioned above // $creationLog = end($logs); - if ($creationLog == false){ + if ( $creationLog == false ) { // retrieve it $creationLog = zeroBSCRM_getObjCreationLog( $contactID, 1 ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -282,51 +286,48 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa } else { // if has creation date (contactObj) - if ($contactObj != false){ + if ( $contactObj != false ) { // manufacture a created log $logsToShow[] = array( - 'id' => -1, - 'created' => $contactObj['created'], - 'name' => '', + 'id' => -1, + 'created' => $contactObj['created'], + 'name' => '', // also add DAL2 support: - 'type' => __('Created',"zero-bs-crm"), - 'shortdesc' => __('Contact Created',"zero-bs-crm"), - 'longdesc' => __('Contact was created',"zero-bs-crm"), - - 'meta' => array( - 'type' => __('Created',"zero-bs-crm"), - 'shortdesc' => __('Contact Created',"zero-bs-crm"), - 'longdesc' => __('Contact was created',"zero-bs-crm") + 'type' => __( 'Created', 'zero-bs-crm' ), + 'shortdesc' => __( 'Contact Created', 'zero-bs-crm' ), + 'longdesc' => __( 'Contact was created', 'zero-bs-crm' ), + + 'meta' => array( + 'type' => __( 'Created', 'zero-bs-crm' ), + 'shortdesc' => __( 'Contact Created', 'zero-bs-crm' ), + 'longdesc' => __( 'Contact was created', 'zero-bs-crm' ), ), - 'owner' => -1, - //nicetime + 'owner' => -1, + // nicetime ); } } - - } - - if ( count($logsToShow) > 0 ) { + if ( count( $logsToShow ) > 0 ) { ?>
    format( zeroBSCRM_getDateFormat() ); // check if same day as prev log @@ -337,16 +338,16 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa $prevDate = $formatted_date; // ico? - $ico = ''; + $ico = ''; $logKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $log['type'] ) ) ); - if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][$logKey] ) ) { - $ico = $zeroBSCRM_logTypes['zerobs_customer'][$logKey]['ico']; + if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ] ) ) { + $ico = $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ]['ico']; } // these are FA ico's at this point // fill in nicetime if using :) // use a setting to turn on off? - if ( !empty( $log['createduts'] ) && $log['createduts'] > 0 ) { + if ( ! empty( $log['createduts'] ) && $log['createduts'] > 0 ) { // get H:i in local timezone $log['nicetime'] = zeroBSCRM_date_i18n( 'H:i', $log['createduts'], true, false ); } @@ -359,12 +360,12 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa // compile this first, so can catch default (empty types) $logTitle = ''; - if ( !empty( $ico ) ) { + if ( ! empty( $ico ) ) { $logTitle .= ' '; } - if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][$logKey] ) ) { - $logTitle .= __( $zeroBSCRM_logTypes['zerobs_customer'][$logKey]['label'], 'zero-bs-crm' ); + if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ] ) ) { + $logTitle .= __( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ]['label'], 'zero-bs-crm' ); } $timeline_item_classes = ''; @@ -374,7 +375,7 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa if ( empty( $logTitle ) ) { $timeline_item_classes .= ' zbs-timeline-item-notitle'; } - if ( !$notLast ) { + if ( ! $notLast ) { $timeline_item_classes .= ' zbs-last-item'; // last item (stop rolling padding) } @@ -386,7 +387,7 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa ?>
  • >
    @@ -399,12 +400,12 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa

    '; } - if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][$logKey] ) ) { - echo esc_html__( $zeroBSCRM_logTypes['zerobs_customer'][$logKey]['label'], 'zero-bs-crm' ); + if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ] ) ) { + echo esc_html__( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ]['label'], 'zero-bs-crm' ); } ?>

    @@ -413,14 +414,14 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa if ( isset( $log['shortdesc'] ) ) { echo wp_kses( $log['shortdesc'], array( 'i' => array( 'class' => true ) ) ); } - if ( !empty( $log['author'] ) ) { + if ( ! empty( $log['author'] ) ) { echo ' — ' . esc_html( $log['author'] ); } if ( isset( $log['nicetime'] ) ) { echo ' — ' . esc_html( $log['nicetime'] ); } // if has long desc, show/hide - if ( !empty( $log['longdesc'] ) ) { + if ( ! empty( $log['longdesc'] ) ) { ?>
    @@ -433,7 +434,7 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa
@@ -441,132 +442,132 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa } } -// /** * Builds HTML table of custom tables & values for (any object type) * * @return string HTML table */ -function zeroBSCRM_pages_admin_display_custom_fields_table($id = -1, $objectType=ZBS_TYPE_CONTACT){ +function zeroBSCRM_pages_admin_display_custom_fields_table( $id = -1, $objectType = ZBS_TYPE_CONTACT ) { global $zbs; // retrieve custom fields (including value) - $custom_fields = $zbs->DAL->getObjectLayerByType($objectType)->getSingleCustomFields($id,false); + $custom_fields = $zbs->DAL->getObjectLayerByType( $objectType )->getSingleCustomFields( $id, false ); // Build HTML - if (is_array($custom_fields) && count($custom_fields) > 0){ + if ( is_array( $custom_fields ) && count( $custom_fields ) > 0 ) { $html = ''; - foreach($custom_fields as $k => $v){ + foreach ( $custom_fields as $k => $v ) { - $html .= ''; - $html .= ''; - switch ($v['type']){ + $html .= ''; + $html .= ''; + switch ( $v['type'] ) { - case 'text': - $value = nl2br( esc_html( $v['value'] ) ); - //if url, build link, prefixed with 'https://' if needed - if ( jpcrm_is_url( $value ) ) { - $value = '' . $value . ''; - } - $html .= ''; - break; + case 'text': + $value = nl2br( esc_html( $v['value'] ) ); + // if url, build link, prefixed with 'https://' if needed + if ( jpcrm_is_url( $value ) ) { + $value = '' . $value . ''; + } + $html .= ''; + break; - case 'date': + case 'date': $html .= ''; - break; + break; - case 'checkbox': - // pad , out - $html .= ''; - break; + case 'checkbox': + // pad , out + $html .= ''; + break; + + default: + $html .= ''; + break; - default: - $html .= ''; - break; + } - } - - $html .= ''; + $html .= ''; } - + $html .= '
' . esc_html($v['name']) . '
' . esc_html( $v['name'] ) . '' . $value . '' . $value . '' . ( $v['value'] !== '' ? jpcrm_uts_to_date_str( $v['value'], false, true ) : '' ) . '' . str_replace(',',', ',esc_html( $v['value'] ) ) . '' . str_replace( ',', ', ', esc_html( $v['value'] ) ) . '' . nl2br( esc_html( $v['value'] ) ) . '' . nl2br( esc_html( $v['value'] ) ) . '
'; } else { - $html = __("No custom fields have been set up yet.", "zero-bs-crm"); - if (zeroBSCRM_isZBSAdminOrAdmin()){ + $html = __( 'No custom fields have been set up yet.', 'zero-bs-crm' ); + if ( zeroBSCRM_isZBSAdminOrAdmin() ) { - $customFieldsUrl = esc_url(admin_url('admin.php?page='.$zbs->slugs['settings']).'&tab=customfields'); - $html .= ' '.__('Click here to manage custom fields', 'zero-bs-crm').''; + $customFieldsUrl = esc_url( admin_url( 'admin.php?page=' . $zbs->slugs['settings'] ) . '&tab=customfields' ); + $html .= ' ' . __( 'Click here to manage custom fields', 'zero-bs-crm' ) . ''; } - - } + } return $html; - } +/* +====================================================== + / Contact + ====================================================== */ -/* ====================================================== - / Contact - ====================================================== */ - - - - -/* ====================================================== - Company - ====================================================== */ +/* +====================================================== + Company + ====================================================== */ /* * Returns company introduction sentence * e.g. Email: alessandra.koepp@example.com, Added 01/01/2022 */ -function zeroBSCRM_html_companyIntroSentence( $company ){ +function zeroBSCRM_html_companyIntroSentence( $company ) { - $return = ""; - if ( isset( $company['email'] ) && !empty( $company['email'] ) ){ - $return .= __('Email:', 'zero-bs-crm'); - $return .= ' ' . $company['email'] . "
"; + $return = ''; + if ( isset( $company['email'] ) && ! empty( $company['email'] ) ) { + $return .= __( 'Email:', 'zero-bs-crm' ); + $return .= ' ' . $company['email'] . '
'; } - if ( is_array( $company ) && $company['created'] > 0 && isset( $company['created_date'] ) ){ + if ( is_array( $company ) && $company['created'] > 0 && isset( $company['created_date'] ) ) { $formatted_date = $company['created_date']; - $return .= __('Added',"zero-bs-crm") . ' ' . $formatted_date; + $return .= __( 'Added', 'zero-bs-crm' ) . ' ' . $formatted_date; } // filter - $return = apply_filters( 'zerobscrm_companyintro_filter', $return, $company['id'] ); - - return $return; + $return = apply_filters( 'zerobscrm_companyintro_filter', $return, $company['id'] ); + return $return; } -function zeroBSCRM_html_linkedCompanyTags($contactID=-1,$tags=false,$classStr=''){ +function zeroBSCRM_html_linkedCompanyTags( $contactID = -1, $tags = false, $classStr = '' ) { global $zbs; - - if ($contactID > 0 && $tags == false) $tags = zeroBSCRM_getCustomerTagsByID($contactID); - if (count($tags) > 0) - foreach ($tags as $tag){ - - // DAL1/2 switch - $tagName = ''; $tagID = -1; - if (is_array($tag)){ - $tagName = $tag['name']; - $tagID = $tag['id']; - } else { - $tagName = $tag->name; - $tagID = $tag->term_id; - } - ?> 0 && $tags == false ) { + $tags = zeroBSCRM_getCustomerTagsByID( $contactID ); + } + if ( count( $tags ) > 0 ) { + foreach ( $tags as $tag ) { + + // DAL1/2 switch + $tagName = ''; + $tagID = -1; + if ( is_array( $tag ) ) { + $tagName = $tag['name']; + $tagID = $tag['id']; + } else { + $tagName = $tag->name; + $tagID = $tag->term_id; + } + + ?> + + 0 && $logs === false){ + if ( isset( $companyID ) && $companyID > 0 && $logs === false ) { // get logs - $logs = zeroBSCRM_getCompanyLogs($companyID,true,100,0,'',false); + $logs = zeroBSCRM_getCompanyLogs( $companyID, true, 100, 0, '', false ); } - // Compile a list of actions to show // - if under 10, show them all // - if over 10, show creation, and 'higher level' logs, then latest // - 7/2/19 WH modified this to catch "creation" logs properly, and always put them at the end // ... (we were getting instances where transaction + contact created in same second, which caused the order to be off) - $logsToShow = array(); $creationLog = false; + $logsToShow = array(); + $creationLog = false; - if (count($logs) <= 10){ + if ( count( $logs ) <= 10 ) { $logsToShow = $logs; - $logsF = array(); $creationLog = false; - // here we have to just do a re-order to make sure created is last :) - foreach ($logsToShow as $l){ + $logsF = array(); + $creationLog = false; + // here we have to just do a re-order to make sure created is last :) + foreach ( $logsToShow as $l ) { - if ($l['type'] == 'created') + if ( $l['type'] == 'created' ) { $creationLog = $l; - else + } else { $logsF[] = $l; - + } } // add it - if (is_array($creationLog)) $logsF[] = $creationLog; + if ( is_array( $creationLog ) ) { + $logsF[] = $creationLog; + } // tidy - $logsToShow = $logsF; - unset($logsF); - unset($creationLog); + $logsToShow = $logsF; + unset( $logsF ); + unset( $creationLog ); } else { // cherry pick 9 logs // 1) latest - $logsToShow[] = current($logs); + $logsToShow[] = current( $logs ); // 2) cherry pick 8 middle events $logTypesToPrioritise = array( - 'Call', - 'Email', - 'Note' - ); - + 'Call', + 'Email', + 'Note', + ); // convert to type stored in db $x = array(); foreach ( $logTypesToPrioritise as $lt ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $x[] = $zbs->DAL->logs->logTypeIn( $lt ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase } - $logTypesToPrioritise = $x; unset($x); - + $logTypesToPrioritise = $x; + unset( $x ); // for now, abbreviated, just cycle through + pick any in prioritised group... could do this staggered by type/time later - foreach ($logs as $l){ - if ($l['type'] == 'created'){ + foreach ( $logs as $l ) { + if ( $l['type'] == 'created' ) { - // add to this var - $creationLog = $l; + // add to this var + $creationLog = $l; - } else { + } else { - // normal pickery - if (count($logsToShow) < 9){ - if (in_array($l['type'], $logTypesToPrioritise)) $logsToShow[] = $l; - } else { - break; + // normal pickery + if ( count( $logsToShow ) < 9 ) { + if ( in_array( $l['type'], $logTypesToPrioritise ) ) { + $logsToShow[] = $l; } - + } else { + break; } - } + } // 3) created // for now, assume first log is created, if it's not, add one with date // ... this'll cover 100+ logs situ - // WH changed 7/2/18 to remove issue mentioned above + // WH changed 7/2/18 to remove issue mentioned above // $creationLog = end($logs); if ( $creationLog == false ) { @@ -704,90 +702,122 @@ function zeroBSCRM_html_companyTimeline($companyID=-1,$logs=false,$companyObj=fa } else { // if has creation date (companyObj) - if ($companyObj != false){ + if ( $companyObj != false ) { // manufacture a created log $logsToShow[] = array( - 'id' => -1, - 'created' => $companyObj['created'], - 'name' => '', + 'id' => -1, + 'created' => $companyObj['created'], + 'name' => '', // also add DAL2 support: - 'type' => __('Created',"zero-bs-crm"), - 'shortdesc' => __(jpcrm_label_company().'Created',"zero-bs-crm"), - 'longdesc' => __(jpcrm_label_company().' was created',"zero-bs-crm"), - - 'meta' => array( - 'type' => __('Created',"zero-bs-crm"), - 'shortdesc' => __(jpcrm_label_company().' Created',"zero-bs-crm"), - 'longdesc' => __(jpcrm_label_company().' was created',"zero-bs-crm") + 'type' => __( 'Created', 'zero-bs-crm' ), + 'shortdesc' => __( jpcrm_label_company() . 'Created', 'zero-bs-crm' ), + 'longdesc' => __( jpcrm_label_company() . ' was created', 'zero-bs-crm' ), + + 'meta' => array( + 'type' => __( 'Created', 'zero-bs-crm' ), + 'shortdesc' => __( jpcrm_label_company() . ' Created', 'zero-bs-crm' ), + 'longdesc' => __( jpcrm_label_company() . ' was created', 'zero-bs-crm' ), ), - 'owner' => -1, - //nicetime + 'owner' => -1, + // nicetime ); } } + } + if ( count( $logsToShow ) > 0 ) { + ?> +
    + format( zeroBSCRM_getDateFormat() ); + + // check if same day as prev log + $sameDate = false; + if ( $formatted_date == $prevDate ) { + $sameDate = true; + } + $prevDate = $formatted_date; + // ico? + $ico = ''; + $logKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $log['type'] ) ) ); + if ( isset( $zeroBSCRM_logTypes['zerobs_company'][ $logKey ] ) ) { + $ico = $zeroBSCRM_logTypes['zerobs_company'][ $logKey ]['ico']; + } + // these are FA ico's at this point - if (count($logsToShow) > 0){ ?> -
      - format(zeroBSCRM_getDateFormat()); - - // check if same day as prev log - $sameDate = false; - if ($formatted_date == $prevDate) $sameDate = true; - $prevDate = $formatted_date; - - // ico? - $ico = ''; $logKey = strtolower(str_replace(' ','_',str_replace(':','_',$log['type']))); - if (isset($zeroBSCRM_logTypes['zerobs_company'][$logKey])) $ico = $zeroBSCRM_logTypes['zerobs_company'][$logKey]['ico']; - // these are FA ico's at this point - - - // fill in nicetime if using :) - // use a setting to turn on off? - if (isset($log['createduts']) && !empty($log['createduts']) && $log['createduts'] > 0){ - //$log['nicetime'] = date('H:i',$log['createduts']); - $log['nicetime'] = zeroBSCRM_date_i18n('H:i', $log['createduts'], true, false); - } - - // if it's last one, make sure it has class: - $notLast = true; if (count($logsToShow) == $i+1) $notLast = false; - - ?> -
    • > -
      - -
      -
      -
      - -
      */ - - ?> -

      '; - if (isset($zeroBSCRM_logTypes['zerobs_company'][$logKey])) echo esc_html( $zeroBSCRM_logTypes['zerobs_company'][$logKey]['label'] ); - ?>

      + // fill in nicetime if using :) + // use a setting to turn on off? + if ( isset( $log['createduts'] ) && ! empty( $log['createduts'] ) && $log['createduts'] > 0 ) { + // $log['nicetime'] = date('H:i',$log['createduts']); + $log['nicetime'] = zeroBSCRM_date_i18n( 'H:i', $log['createduts'], true, false ); + } + + // if it's last one, make sure it has class: + $notLast = true; + if ( count( $logsToShow ) == $i + 1 ) { + $notLast = false; + } + + ?> +
    • + > + +
      + +
      +
      +
      + + +
      */ + + ?> +

      + '; + } + if ( isset( $zeroBSCRM_logTypes['zerobs_company'][ $logKey ] ) ) { + echo esc_html( $zeroBSCRM_logTypes['zerobs_company'][ $logKey ]['label'] ); + } + ?> +

      -
- - - - + + + + '.zeroBSCRM_getObjNav($zbsid,'edit','CONTACT').'
'; @@ -961,7 +995,7 @@ function zeroBSCRM_getObjNav( $id = -1, $key = '', $type = ZBS_TYPE_CONTACT ) { global $zbs; - $html = ''; + $html = ''; $navigation_mode = $zbs->settings->get( 'objnav' ); // The first addition of a contact is actually 'edit' but gives the option to view. @@ -969,10 +1003,9 @@ function zeroBSCRM_getObjNav( $id = -1, $key = '', $type = ZBS_TYPE_CONTACT ) { $html = ''; - switch ($type) { + switch ( $type ) { case ZBS_TYPE_CONTACT: - // contact nav $navigation = $zbs->DAL->contacts->getContactPrevNext( $id ); @@ -991,7 +1024,6 @@ function zeroBSCRM_getObjNav( $id = -1, $key = '', $type = ZBS_TYPE_CONTACT ) { break; case ZBS_TYPE_COMPANY: - // company nav $navigation = $zbs->DAL->companies->getCompanyPrevNext( $id ); @@ -1016,12 +1048,12 @@ function zeroBSCRM_getObjNav( $id = -1, $key = '', $type = ZBS_TYPE_CONTACT ) { } return $html; - } -/* ====================================================== - / Object Nav - ====================================================== */ +/* +====================================================== + / Object Nav + ====================================================== */ /** * Return table options button @@ -1030,18 +1062,20 @@ function get_jpcrm_table_options_button() { return ''; } -/* ====================================================== - Tasks - ====================================================== */ - - function zeroBSCRM_html_taskStatusLabel($task=array()){ - - if (isset($task['complete']) && $task['complete'] === 1) return 'ui green label'; +/* +====================================================== + Tasks + ====================================================== */ - return 'ui grey label'; +function zeroBSCRM_html_taskStatusLabel( $task = array() ) { + if ( isset( $task['complete'] ) && $task['complete'] === 1 ) { + return 'ui green label'; } + return 'ui grey label'; +} + /** * Returns a task datetime range string * @@ -1067,15 +1101,15 @@ function zeroBSCRM_html_taskDate( $task = array() ) { return $task_start . ' - ' . $task_end; } -/* ====================================================== - / Tasks - ====================================================== */ - - +/* +====================================================== + / Tasks + ====================================================== */ -/* ====================================================== - Email History - ====================================================== */ +/* +====================================================== + Email History + ====================================================== */ function zeroBSCRM_outputEmailHistory( $user_id = -1 ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid,Squiz.Commenting.FunctionComment.Missing,Squiz.Commenting.FunctionComment.WrongStyle @@ -1205,87 +1239,88 @@ function zeroBSCRM_outputEmailHistory( $user_id = -1 ) { // phpcs:ignore WordPre } } -/* ====================================================== - / Email History - ====================================================== */ - - -/* ====================================================== - Edit Pages Field outputter - ====================================================== */ - - // puts out edit fields for an object (e.g. quotes) - // centralisd/genericified 20/7/18 wh 2.91+ - function zeroBSCRM_html_editFields($objArr=false,$fields=false,$postPrefix='zbs_',$skipFields=array()){ +/* +====================================================== + / Email History + ====================================================== */ - if (is_array($fields)){ +/* +====================================================== + Edit Pages Field outputter + ====================================================== */ - foreach ($fields as $fieldK => $fieldV){ + // puts out edit fields for an object (e.g. quotes) + // centralisd/genericified 20/7/18 wh 2.91+ +function zeroBSCRM_html_editFields( $objArr = false, $fields = false, $postPrefix = 'zbs_', $skipFields = array() ) { - // we skip some when we put them out specifically/manually in the metabox/ui - if (!in_array($fieldK,$skipFields)) zeroBSCRM_html_editField($objArr,$fieldK,$fieldV,$postPrefix); + if ( is_array( $fields ) ) { - } + foreach ( $fields as $fieldK => $fieldV ) { - } - } + // we skip some when we put them out specifically/manually in the metabox/ui + if ( ! in_array( $fieldK, $skipFields ) ) { + zeroBSCRM_html_editField( $objArr, $fieldK, $fieldV, $postPrefix ); + } + } + } +} - // puts out edit field for an object (e.g. quotes) - // centralisd/genericified 20/7/18 wh 2.91+ - function zeroBSCRM_html_editField($dataArr=array(), $fieldKey = false, $fieldVal = false, $postPrefix = 'zbs_'){ - // phpcs:disable + // puts out edit field for an object (e.g. quotes) + // centralisd/genericified 20/7/18 wh 2.91+ +function zeroBSCRM_html_editField( $dataArr = array(), $fieldKey = false, $fieldVal = false, $postPrefix = 'zbs_' ) { + // phpcs:disable /* debug if ($fieldKey == 'house-type') { - echo ''.$fieldKey.'
'.print_r(array($fieldVal,$dataArr),1).'
'; + echo ''.$fieldKey.'
'.print_r(array($fieldVal,$dataArr),1).'
'; } */ - if (!empty($fieldKey) && is_array($fieldVal)){ + if (!empty($fieldKey) && is_array($fieldVal)){ - // infer a default (Added post objmodels v3.0 as a potential.) - $default = ''; if (is_array($fieldVal) && isset($fieldVal['default'])) $default = $fieldVal['default']; + // infer a default (Added post objmodels v3.0 as a potential.) + $default = ''; if (is_array($fieldVal) && isset($fieldVal['default'])) $default = $fieldVal['default']; - // get a value (this allows field-irrelevant global tweaks, like the addr catch below...) - // -99 = notset - $value = -99; if (isset($dataArr[$fieldKey])) $value = $dataArr[$fieldKey]; + // get a value (this allows field-irrelevant global tweaks, like the addr catch below...) + // -99 = notset + $value = -99; if (isset($dataArr[$fieldKey])) $value = $dataArr[$fieldKey]; - // custom classes for inputs - $inputClasses = isset($fieldVal['custom-field']) ? ' zbs-custom-field' : ''; + // custom classes for inputs + $inputClasses = isset($fieldVal['custom-field']) ? ' zbs-custom-field' : ''; - // contacts got stuck in limbo as we upgraded db in 2 phases. - // following catches old str and modernises to v3.0 - // make addresses their own objs 3.0+ and do away with this. - // ... hard typed to avoid custom field collisions, hacky at best. - switch ($fieldKey){ + // contacts got stuck in limbo as we upgraded db in 2 phases. + // following catches old str and modernises to v3.0 + // make addresses their own objs 3.0+ and do away with this. + // ... hard typed to avoid custom field collisions, hacky at best. + switch ($fieldKey){ - case 'secaddr1': - if (isset($dataArr['secaddr_addr1'])) $value = $dataArr['secaddr_addr1']; - break; + case 'secaddr1': + if (isset($dataArr['secaddr_addr1'])) $value = $dataArr['secaddr_addr1']; + break; - case 'secaddr2': + case 'secaddr2': if (isset($dataArr['secaddr_addr2'])) $value = $dataArr['secaddr_addr2']; - break; + break; - case 'seccity': - if (isset($dataArr['secaddr_city'])) $value = $dataArr['secaddr_city']; - break; + case 'seccity': + if (isset($dataArr['secaddr_city'])) $value = $dataArr['secaddr_city']; + break; - case 'seccounty': - if (isset($dataArr['secaddr_county'])) $value = $dataArr['secaddr_county']; - break; + case 'seccounty': + if (isset($dataArr['secaddr_county'])) $value = $dataArr['secaddr_county']; + break; - case 'seccountry': - if (isset($dataArr['secaddr_country'])) $value = $dataArr['secaddr_country']; - break; + case 'seccountry': + if (isset($dataArr['secaddr_country'])) $value = $dataArr['secaddr_country']; + break; - case 'secpostcode': - if (isset($dataArr['secaddr_postcode'])) $value = $dataArr['secaddr_postcode']; - break; - } + case 'secpostcode': + if (isset($dataArr['secaddr_postcode'])) $value = $dataArr['secaddr_postcode']; + break; + } - global $zbs; + global $zbs; switch ( $fieldVal[0] ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - case 'text': + case 'text': ?>
@@ -1311,7 +1346,7 @@ class="form-control widetext zbs-dc
- + " />
-
-
- settings->get('showprefix') == 0 && $fieldKey == 'prefix') { - break; - } + //don't load prefix select if prefix is hidden in settings + if ($zbs->settings->get('showprefix') == 0 && $fieldKey == 'prefix') { + break; + } ?>
- settings->get('clicktocall'); + // Click 2 call? + $click2call = $zbs->settings->get('clicktocall'); ?>
@@ -1465,37 +1500,37 @@ class="form-control intOnly zbs-dc - ' . esc_html( $value ) . ''; ?> + ' . esc_html( $value ) . ''; ?> - '. esc_html__('SMS','zero-bs-crm').': ' . esc_html( $customerMob ) . ''; + if (!empty($customerMob)) echo ' '. esc_html__('SMS','zero-bs-crm').': ' . esc_html( $customerMob ) . ''; - } + } - ?> + ?>
- - // removed from email for now zbs-text-input + // added zbs-text-input class 5/1/18 - this allows "linkify" automatic linking + // ... via js
+ // removed from email for now zbs-text-input ?>
@@ -1506,9 +1541,9 @@ class="form-control intOnly zbs-dc
- ">:
-
- - '; + // we also output as input, which stops any overwriting + makes new ones for new records + echo ''; - ?> + ?>
-
- 0){ - if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ + //if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){ + if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ - $optIndex = 0; + $optIndex = 0; - foreach ($options as $opt){ + foreach ($options as $opt){ - echo '
'; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ($value !== -99 && $value == $opt) echo ' checked="checked"'; + echo ' />
'; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $optIndex++; + $optIndex++; - } + } - } else { - echo ''; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } - ?> + } else { + echo ''; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } + ?>
-
- 0){ - if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ + //if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){ + if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ - $optIndex = 0; + $optIndex = 0; - foreach ($options as $opt){ + foreach ($options as $opt){ - echo '
'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + echo '
'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $optIndex++; + $optIndex++; - } + } - } else { - echo ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + } else { + echo ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - ?> + ?>
- - '.$fieldKey.'
'.print_r(array($fieldVal,$dataArr),1).'
'; +echo ''.$fieldKey.'
'.print_r(array($fieldVal,$dataArr),1).'
'; } */ - if (!empty($fieldKey) && is_array($fieldVal)){ +if (!empty($fieldKey) && is_array($fieldVal)){ - // infer a default (Added post objmodels v3.0 as a potential.) - $default = ''; if (is_array($fieldVal) && isset($fieldVal['default'])) $default = $fieldVal['default']; + // infer a default (Added post objmodels v3.0 as a potential.) + $default = ''; if (is_array($fieldVal) && isset($fieldVal['default'])) $default = $fieldVal['default']; - // get a value (this allows field-irrelevant global tweaks, like the addr catch below...) - // -99 = notset - $value = -99; if (isset($dataArr[$fieldKey])) $value = $dataArr[$fieldKey]; + // get a value (this allows field-irrelevant global tweaks, like the addr catch below...) + // -99 = notset + $value = -99; if (isset($dataArr[$fieldKey])) $value = $dataArr[$fieldKey]; - // custom classes for inputs - $inputClasses = isset($fieldVal['custom-field']) ? ' zbs-custom-field' : ''; + // custom classes for inputs + $inputClasses = isset($fieldVal['custom-field']) ? ' zbs-custom-field' : ''; - // contacts got stuck in limbo as we upgraded db in 2 phases. - // following catches old str and modernises to v3.0 - // make addresses their own objs 3.0+ and do away with this. - // ... hard typed to avoid custom field collisions, hacky at best. - switch ($fieldKey){ + // contacts got stuck in limbo as we upgraded db in 2 phases. + // following catches old str and modernises to v3.0 + // make addresses their own objs 3.0+ and do away with this. + // ... hard typed to avoid custom field collisions, hacky at best. + switch ($fieldKey){ - case 'secaddr1': - if (isset($dataArr['secaddr_addr1'])) $value = $dataArr['secaddr_addr1']; - break; + case 'secaddr1': + if (isset($dataArr['secaddr_addr1'])) $value = $dataArr['secaddr_addr1']; + break; - case 'secaddr2': + case 'secaddr2': if (isset($dataArr['secaddr_addr2'])) $value = $dataArr['secaddr_addr2']; - break; + break; - case 'seccity': - if (isset($dataArr['secaddr_city'])) $value = $dataArr['secaddr_city']; - break; + case 'seccity': + if (isset($dataArr['secaddr_city'])) $value = $dataArr['secaddr_city']; + break; - case 'seccounty': - if (isset($dataArr['secaddr_county'])) $value = $dataArr['secaddr_county']; - break; + case 'seccounty': + if (isset($dataArr['secaddr_county'])) $value = $dataArr['secaddr_county']; + break; - case 'seccountry': - if (isset($dataArr['secaddr_country'])) $value = $dataArr['secaddr_country']; - break; + case 'seccountry': + if (isset($dataArr['secaddr_country'])) $value = $dataArr['secaddr_country']; + break; - case 'secpostcode': - if (isset($dataArr['secaddr_postcode'])) $value = $dataArr['secaddr_postcode']; - break; - } - global $zbs; + case 'secpostcode': + if (isset($dataArr['secaddr_postcode'])) $value = $dataArr['secaddr_postcode']; + break; + } + global $zbs; - switch ($fieldVal[0]){ + switch ($fieldVal[0]){ - case 'text': + case 'text': - ?> + ?>
@@ -1815,7 +1850,7 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal break; - case 'price': + case 'price': ?> @@ -1826,9 +1861,9 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal break; - case 'numberfloat': + case 'numberfloat': - ?> + ?> @@ -1837,9 +1872,9 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal break; - case 'numberint': + case 'numberint': - ?> + ?> @@ -1850,32 +1885,32 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal case 'date': - $datevalue = ''; + $datevalue = ''; - if ( $value !== -99 ) { - $datevalue = jpcrm_uts_to_date_str( $value, 'Y-m-d', true ); - } + if ( $value !== -99 ) { + $datevalue = jpcrm_uts_to_date_str( $value, 'Y-m-d', true ); + } - // if this is a custom field, and is unset, we let it get passed as empty (gh-56) - if ( isset( $fieldVal['custom-field'] ) && ( $value === -99 || $value === '' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // if this is a custom field, and is unset, we let it get passed as empty (gh-56) + if ( isset( $fieldVal['custom-field'] ) && ( $value === -99 || $value === '' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $datevalue = ''; - } - ?> + } + ?> - + ?> @@ -1884,47 +1919,47 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal break; - case 'select': + case 'select': //don't load prefix select if prefix is hidden in settings if ($zbs->settings->get('showprefix') == 0 && $fieldKey == 'prefix') { - break; + break; } - ?> + ?> @@ -1952,16 +1987,16 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal if ($fieldKey == 'mobtel'){ - $sms_class = 'send-sms-none'; - $sms_class = apply_filters('zbs_twilio_sms', $sms_class); - do_action('zbs_twilio_nonce'); + $sms_class = 'send-sms-none'; + $sms_class = apply_filters('zbs_twilio_sms', $sms_class); + do_action('zbs_twilio_nonce'); - $customerMob = ''; - // wh genericified - //if (is_array($dataArr) && isset($dataArr[$fieldKey]) && isset($dataArr['id'])) $customerMob = zeroBS_customerMobile($dataArr['id'],$dataArr); - if ($value !== -99) $customerMob = $value; + $customerMob = ''; + // wh genericified + //if (is_array($dataArr) && isset($dataArr[$fieldKey]) && isset($dataArr['id'])) $customerMob = zeroBS_customerMobile($dataArr['id'],$dataArr); + if ($value !== -99) $customerMob = $value; - if (!empty($customerMob)) echo ' '. esc_html__('SMS','zero-bs-crm').': ' . esc_html( $customerMob ) . ''; + if (!empty($customerMob)) echo ' '. esc_html__('SMS','zero-bs-crm').': ' . esc_html( $customerMob ) . ''; } @@ -1970,13 +2005,13 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal break; - case 'email': + case 'email': - // added zbs-text-input class 5/1/18 - this allows "linkify" automatic linking - // ... via js
- // removed from email for now zbs-text-input + // added zbs-text-input class 5/1/18 - this allows "linkify" automatic linking + // ... via js
+ // removed from email for now zbs-text-input - ?> + ?>
@@ -1987,21 +2022,21 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal break; - case 'textarea': + case 'textarea': - ?> + ?> + ?> '; - ?> + ?> + ?>
- 0){ - if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ + //if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){ + if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ - $optIndex = 0; + $optIndex = 0; - foreach ($options as $opt){ + foreach ($options as $opt){ - echo '
'; + if ($value !== -99 && $value == $opt) echo ' checked="checked"'; + echo ' />
'; - $optIndex++; + $optIndex++; - } + } } else echo ''; // @@ -2112,10 +2147,10 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal break; - // checkbox - case 'checkbox': + // checkbox + case 'checkbox': - ?> + ?>
0){ if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ - $optIndex = 0; + $optIndex = 0; - foreach ($options as $opt){ + foreach ($options as $opt){ - echo '
'; + echo '
'; - $optIndex++; + $optIndex++; } @@ -2160,10 +2195,10 @@ function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = fal break; - // tax - case 'tax': + // tax + case 'tax': - ?> + ?> -

+ */ + public function form( $instance ) { + if ( isset( $instance['title'] ) ) { + $title = $instance['title']; + } else { + $title = __( 'Contact us', 'zero-bs-crm' ); + } + if ( isset( $instance['style'] ) ) { + $style = $instance['style']; + } else { + $style = __( 'Simple', 'zero-bs-crm' ); + } + if ( isset( $instance['id'] ) ) { + $id = $instance['id']; + } else { + $id = 0; + } + ?> +

+ + +

- -

- -

- - -

- - get_field_id( 'text' ) ); ?>">Style: + + +

+ +

+ + +

+ + "; @@ -213,47 +217,47 @@ function zeroBSCRM_forms_formHTMLHeader(){ echo ''; } - } -add_action('wp_head', 'zeroBSCRM_forms_formHTMLHeader'); +add_action( 'wp_head', 'zeroBSCRM_forms_formHTMLHeader' ); // return html of form -function zeroBSCRM_forms_build_form_html($formID=-1, $formStyle='content', $fallbackMessage=''){ +function zeroBSCRM_forms_build_form_html( $formID = -1, $formStyle = 'content', $fallbackMessage = '' ) { // check form ID & style - if ($formID > 0 && in_array($formStyle,array('naked','content','simple','cgrab'))){ + if ( $formID > 0 && in_array( $formStyle, array( 'naked', 'content', 'simple', 'cgrab' ) ) ) { // 'cgrab' was original 'content' - if ($formStyle === 'cgrab') $formStyle = 'content'; + if ( $formStyle === 'cgrab' ) { + $formStyle = 'content'; + } // retrieve Form - $form = zeroBS_getForm($formID); + $form = zeroBS_getForm( $formID ); #} This checks it found something - if (is_array($form)){ + if ( is_array( $form ) ) { return call_user_func( 'jpcrm_' . $formStyle . '_form_html', $formID, $form ); } - } return $fallbackMessage; } // return HTML for ReCaptcha (if using) -function zeroBSCRM_forms_getRecaptcha(){ +function zeroBSCRM_forms_getRecaptcha() { #} reCaptcha addition - $reCaptcha = zeroBSCRM_getSetting('usegcaptcha'); - $reCaptchaKey = zeroBSCRM_getSetting('gcaptchasitekey'); - if ($reCaptcha && !empty($reCaptchaKey)) return '
'; + $reCaptcha = zeroBSCRM_getSetting( 'usegcaptcha' ); + $reCaptchaKey = zeroBSCRM_getSetting( 'gcaptchasitekey' ); + if ( $reCaptcha && ! empty( $reCaptchaKey ) ) { + return '
'; + } return ''; - } - // v3 form HTML builder (simple style) function jpcrm_simple_form_html( $formid = -1, $formObject = array() ) { @@ -262,38 +266,40 @@ function jpcrm_simple_form_html( $formid = -1, $formObject = array() ) { ?>
-
+
-

-

+

+

- " value=""/> + - "/> +
-
+
-
+
settings->get( 'showpoweredby_public' ) === 1 ? true : false; - if( $showpoweredby_public ) { - ?>
Powered by Jetpack CRM
+
Powered by Jetpack CRM
+
-
-
+
- " value=""/> - " value=""/> + + - "/> +
-
+
-
+
settings->get( 'showpoweredby_public' ) === 1 ? true : false; - if( $showpoweredby_public ) { - ?>
Powered by Jetpack CRM
+
Powered by Jetpack CRM
+
-
-
+
-

-

+

+

- " value=""/> - " value=""/> - " value=""/> - + + + + - "/> +
-
+
-
+
settings->get( 'showpoweredby_public' ) === 1 ? true : false; - if( $showpoweredby_public ) { - ?>
Powered by Jetpack CRM
+
Powered by Jetpack CRM
+
- ! - return $obj; + if ( $return ) { + return $x; + } + // this'll never work? echo $x; - break; + break; + default: + // NON str/arr... should not be using this for them>! + return $obj; - } + break; } +} /** * Recursively strips slashes from an array. @@ -155,37 +157,38 @@ function zeroBSCRM_stripSlashesFromArr( $value ) { // phpcs:ignore WordPress.Nam return $value; } - # from http://wordpress.stackexchange.com/questions/91900/how-to-force-a-404-on-wordpress - function zeroBSCRM_force_404() { - status_header( 404 ); - nocache_headers(); - include get_query_template( '404' ); - die( 0 ); - } + # from http://wordpress.stackexchange.com/questions/91900/how-to-force-a-404-on-wordpress +function zeroBSCRM_force_404() { + status_header( 404 ); + nocache_headers(); + include get_query_template( '404' ); + die( 0 ); +} // WH not sure why we need this, shuttled off into zeroBSCRM_generateHash which is cleaner. - function zeroBSCRM_GenerateHashForPost($postID=-1,$length=20){ - - #} Brutal hash generator, for now - if (!empty($postID)){ - - return zeroBSCRM_generateHash($length); +function zeroBSCRM_GenerateHashForPost( $postID = -1, $length = 20 ) { - } + #} Brutal hash generator, for now + if ( ! empty( $postID ) ) { - return ''; + return zeroBSCRM_generateHash( $length ); } - // WH centralised, we had zeroBSCRM_GenerateHashForPost - but as moving away from CPT's not sure why - function zeroBSCRM_generateHash($length=20){ - - $genLen = 20; if ($genLen < $length) $genLen = $length; - $newMD5 = wp_generate_password($genLen, false); + return ''; +} - return substr($newMD5,0,$length-1); + // WH centralised, we had zeroBSCRM_GenerateHashForPost - but as moving away from CPT's not sure why +function zeroBSCRM_generateHash( $length = 20 ) { + $genLen = 20; + if ( $genLen < $length ) { + $genLen = $length; } + $newMD5 = wp_generate_password( $genLen, false ); + + return substr( $newMD5, 0, $length - 1 ); +} /* * Creates an MD5 hash of $obj, (typically an array) @@ -194,71 +197,78 @@ function zeroBSCRM_generateHash($length=20){ * @param $obj - {anything} * @return string - md5 of $obj, json encoded and sorted */ - function jpcrm_generate_hash_of_obj( $obj ){ - - // note this will return different if sort order different - return md5( json_encode( $obj ) ); - } +function jpcrm_generate_hash_of_obj( $obj ) { - function zeroBSCRM_loadCountryList(){ - #} load country list - global $zeroBSCRM_countries; - if(!isset($zeroBSCRM_countries)) require_once( ZEROBSCRM_INCLUDE_PATH . 'wh.countries.lib.php'); + // note this will return different if sort order different + return md5( json_encode( $obj ) ); +} - return $zeroBSCRM_countries; +function zeroBSCRM_loadCountryList() { + #} load country list + global $zeroBSCRM_countries; + if ( ! isset( $zeroBSCRM_countries ) ) { + require_once ZEROBSCRM_INCLUDE_PATH . 'wh.countries.lib.php'; } - function zeroBSCRM_uniqueID(){ - + return $zeroBSCRM_countries; +} + +function zeroBSCRM_uniqueID() { + #} When you're wrapping a func in another, and you're guaranteed it'll return a val, can just do this: - #} When you're wrapping a func in another, and you're guaranteed it'll return a val, can just do this: - - $prefix = 'ab33id_'; - ##WLREMOVE - $prefix = 'crmt_'; - ##/WLREMOVE - - return uniqid($prefix); + $prefix = 'ab33id_'; + ##WLREMOVE + $prefix = 'crmt_'; + ##/WLREMOVE - } + return uniqid( $prefix ); +} - function zeroBSCRM_ifV($v){ - if (isset($v)) echo $v; +function zeroBSCRM_ifV( $v ) { + if ( isset( $v ) ) { + echo $v; } +} // if is array and has value v, else - function zbs_ifAV($a=array(),$v='',$else=false){ - if (is_array($a) && isset($a[$v])) return $a[$v]; - return $else; - } - - function zbs_prettyprint($array){ - echo '
';
-	    var_dump($array);
-	    echo '
'; +function zbs_ifAV( $a = array(), $v = '', $else = false ) { + if ( is_array( $a ) && isset( $a[ $v ] ) ) { + return $a[ $v ]; } + return $else; +} +function zbs_prettyprint( $array ) { + echo '
';
+	var_dump( $array );
+	echo '
'; +} - function zeroBS_delimiterIf($delimiter,$ifStr=''){ - - if (!empty($ifStr)) return $delimiter; +function zeroBS_delimiterIf( $delimiter, $ifStr = '' ) { - return ''; + if ( ! empty( $ifStr ) ) { + return $delimiter; } + return ''; +} // BE INCREADIBLY CAREFUL WITH THIS FUNC, it'll recursively delete a directory // ... safety mechanism put in - if not defined will die :) -function zeroBSCRM_del($dir) { +function zeroBSCRM_del( $dir ) { - if (!defined('ZBS_OKAY_TO_PROCEED')) exit('CANNOT'); - if (file_exists($dir) && is_dir($dir)){ - $files = array_diff(scandir($dir), array('.','..')); - if (is_array($files)) foreach ($files as $file) { - (is_dir("$dir/$file")) ? zeroBSCRM_del("$dir/$file") : unlink("$dir/$file"); - } - return rmdir($dir); + if ( ! defined( 'ZBS_OKAY_TO_PROCEED' ) ) { + exit( 'CANNOT' ); + } + if ( file_exists( $dir ) && is_dir( $dir ) ) { + $files = array_diff( scandir( $dir ), array( '.', '..' ) ); + if ( is_array( $files ) ) { + foreach ( $files as $file ) { + ( is_dir( "$dir/$file" ) ) ? zeroBSCRM_del( "$dir/$file" ) : unlink( "$dir/$file" ); + } + } + return rmdir( $dir ); } } @@ -269,17 +279,17 @@ function zeroBSCRM_del($dir) { * @param bool $also_remove_hidden_files - shall we also clear files like .htaccess? * */ -function jpcrm_delete_files_from_directory( $directory_path, $also_remove_hidden_files = false ){ +function jpcrm_delete_files_from_directory( $directory_path, $also_remove_hidden_files = false ) { - if ( !is_dir( $directory_path ) ){ + if ( ! is_dir( $directory_path ) ) { return false; } - if ( $also_remove_hidden_files ){ + if ( $also_remove_hidden_files ) { - $files = glob( $directory_path . '{,.}*', GLOB_BRACE); + $files = glob( $directory_path . '{,.}*', GLOB_BRACE ); } else { @@ -288,228 +298,211 @@ function jpcrm_delete_files_from_directory( $directory_path, $also_remove_hidden } // cycle through - foreach( $files as $file ){ - - if ( is_file( $file ) ) { - - unlink( $file ); + foreach ( $files as $file ) { - } + if ( is_file( $file ) ) { + unlink( $file ); + + } } } - function zeroBSCRM_user_last_login( $user_login, $user ) { - update_user_meta( $user->ID, 'last_login', time() ); + update_user_meta( $user->ID, 'last_login', time() ); } add_action( 'wp_login', 'zeroBSCRM_user_last_login', 10, 2 ); - function zeroBSCRM_currentUser_email() { - $current_user = wp_get_current_user(); - return $current_user->user_email; + $current_user = wp_get_current_user(); + return $current_user->user_email; } function zeroBSCRM_currentUser_displayName() { - $current_user = wp_get_current_user(); - return $current_user->display_name; + $current_user = wp_get_current_user(); + return $current_user->display_name; } /** * Retrieve users of a specific wp role */ -function jpcrm_wordpress_users_with_role( $role = '' ) { +function jpcrm_wordpress_users_with_role( $role = '' ) { // needs role - if (empty($role)) return array(); + if ( empty( $role ) ) { + return array(); + } // retreive & return $args = array( - 'role' => $role, - 'orderby' => 'user_nicename', - 'order' => 'ASC' + 'role' => $role, + 'orderby' => 'user_nicename', + 'order' => 'ASC', ); return get_users( $args ); - } - /** * Retrieve users with one of an array of specific wp roles */ -function jpcrm_wordpress_users_with_role_in( $roles = array() ) { +function jpcrm_wordpress_users_with_role_in( $roles = array() ) { // needs to be an array of roles - if ( !is_array($roles) ) return array(); + if ( ! is_array( $roles ) ) { + return array(); + } // retreive & return $args = array( - 'role__in' => $roles, - 'orderby' => 'user_nicename', - 'order' => 'ASC' + 'role__in' => $roles, + 'orderby' => 'user_nicename', + 'order' => 'ASC', ); return get_users( $args ); - } - /** * Display last login time - * */ - -function zeroBSCRM_wpb_lastlogin($uid ) { - $last_login = get_user_meta( $uid, 'last_login',true); - if($last_login == ''){ - $the_login_date = __("Never","zero-bs-crm"); - }else{ - $the_login_date = human_time_diff($last_login); +function zeroBSCRM_wpb_lastlogin( $uid ) { + $last_login = get_user_meta( $uid, 'last_login', true ); + if ( $last_login == '' ) { + $the_login_date = __( 'Never', 'zero-bs-crm' ); + } else { + $the_login_date = human_time_diff( $last_login ); } - return $the_login_date; -} - - + return $the_login_date; +} #} Pretty up long numbers - function zeroBSCRM_prettifyLongInts($i){ - - if ((int)$i > 999){ - return number_format($i); - } else { - if (zeroBSCRM_numberOfDecimals($i) > 2) return round($i,2); else return $i; - } - - } +function zeroBSCRM_prettifyLongInts( $i ) { - // Brutal. http://snipplr.com/view/39450/ - function zeroBSCRM_prettyAbbr($size) { - $size = preg_replace('/[^0-9]/','',$size); - $sizes = array("", "k", "m"); - if ($size == 0) { return('n/a'); } else { - return (round($size/pow(1000, ($i = floor(log($size, 1000)))), 0) . $sizes[$i]); } + if ( (int) $i > 999 ) { + return number_format( $i ); + } elseif ( zeroBSCRM_numberOfDecimals( $i ) > 2 ) { + return round( $i, 2 ); + } else { + return $i; } +} + // Brutal. http://snipplr.com/view/39450/ +function zeroBSCRM_prettyAbbr( $size ) { + $size = preg_replace( '/[^0-9]/', '', $size ); + $sizes = array( '', 'k', 'm' ); + if ( $size == 0 ) { + return( 'n/a' ); } else { + return ( round( $size / pow( 1000, ( $i = floor( log( $size, 1000 ) ) ) ), 0 ) . $sizes[ $i ] ); } +} #} how many decimal points? - function zeroBSCRM_numberOfDecimals($value) - { - if ((int)$value == $value) - { - return 0; - } - else if (! is_numeric($value)) - { - return false; - } - - return strlen($value) - strrpos($value, '.') - 1; +function zeroBSCRM_numberOfDecimals( $value ) { + if ( (int) $value == $value ) { + return 0; + } elseif ( ! is_numeric( $value ) ) { + return false; } + return strlen( $value ) - strrpos( $value, '.' ) - 1; +} - function zeroBSCRM_mtime_float(){ - list($usec, $sec) = explode(" ", microtime()); - return ((float)$usec + (float)$sec); - } +function zeroBSCRM_mtime_float() { + list($usec, $sec) = explode( ' ', microtime() ); + return ( (float) $usec + (float) $sec ); +} #} Does its best to find the real IP for user - function zeroBSCRM_getRealIpAddr() - { - $ip = false; - #} check ip from share internet - if (isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP'])) - { - $ip=$_SERVER['HTTP_CLIENT_IP']; - } - #} To check ip is pass from proxy - elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) - { - $ip=$_SERVER['HTTP_X_FORWARDED_FOR']; - } - elseif (isset($_SERVER['REMOTE_ADDR'])) - { - $ip=$_SERVER['REMOTE_ADDR']; - } - return $ip; - } +function zeroBSCRM_getRealIpAddr() { + $ip = false; + #} check ip from share internet + if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) && ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { + $ip = $_SERVER['HTTP_CLIENT_IP']; + } + #} To check ip is pass from proxy + elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) && ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { + $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) { + $ip = $_SERVER['REMOTE_ADDR']; + } + return $ip; +} // from https://stackoverflow.com/questions/5800927/how-to-identify-server-ip-address-in-php - function zeroBSCRM_getServerIP(){ +function zeroBSCRM_getServerIP() { - $ip = false; + $ip = false; // this method is spoofable/not safe on all hosts // non iis if ( ! empty( $_SERVER['SERVER_ADDR'] ) ) { $ip = $_SERVER['SERVER_ADDR']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized } - // iis - if (!$ip && isset($_SERVER['LOCAL_ADDR']) && !empty($_SERVER['LOCAL_ADDR'])) $ip = $_SERVER['LOCAL_ADDR']; - - - // this method uses dns - if (!$ip){ - $host= gethostname(); - $ip = gethostbyname($host); - } + // iis + if ( ! $ip && isset( $_SERVER['LOCAL_ADDR'] ) && ! empty( $_SERVER['LOCAL_ADDR'] ) ) { + $ip = $_SERVER['LOCAL_ADDR']; + } - return $ip; + // this method uses dns + if ( ! $ip ) { + $host = gethostname(); + $ip = gethostbyname( $host ); } - + return $ip; +} + // deprecated 4.0.9 - function zeroBSCRM_ip_country() - { - - return ''; - /* - $ip = zeroBSCRM_getRealIpAddr(); $ip_data = false; - $country = "Unknown"; - - $ip_data_in = wp_remote_get( 'http://www.geoplugin.net/json.gp?ip='.$ip, array( - 'timeout' => 15 - ) - ); +function zeroBSCRM_ip_country() { - if ( is_wp_error( $ip_data_in ) ) { - - //$error_message = $response->get_error_message(); - //echo "Something went wrong: $error_message"; + return ''; + /* + $ip = zeroBSCRM_getRealIpAddr(); $ip_data = false; + $country = "Unknown"; - } else { + $ip_data_in = wp_remote_get( 'http://www.geoplugin.net/json.gp?ip='.$ip, array( + 'timeout' => 15 + ) + ); - if (is_array($ip_data_in['body']) && isset($ip_data_in['body']) && is_string($ip_data_in['body'])){ - $ip_data = json_decode($ip_data_in['body'],true); - $ip_data = str_replace('"', '"', $ip_data); // for PHP 5.2 see stackoverflow.com/questions/3110487/ - } - } - - if (is_array($ip_data) && $ip_data && $ip_data['geoplugin_countryName'] != null) { - $country = $ip_data['geoplugin_countryName']; - } - - return $country; - */ - } + if ( is_wp_error( $ip_data_in ) ) { + //$error_message = $response->get_error_message(); + //echo "Something went wrong: $error_message"; - function zeroBSCRM_findAB($html,$first,$nextStr,$fallbackCloser='open($filepath); - if ($res === TRUE) { - $zip->extractTo($expandTo); - $zip->close(); - return true; - } + if ( file_exists( $filepath ) && file_exists( $expandTo ) ) { + $zip = new ZipArchive(); + $res = $zip->open( $filepath ); + if ( $res === true ) { + $zip->extractTo( $expandTo ); + $zip->close(); + return true; } - - } catch (Exception $ex){ - - } + } catch ( Exception $ex ) { - } else { + } + } else { - // No ZipArchive, fallback to WP's included PclZip - // .. we used to package our own copy of this, but it was flagging as malware. See GH-1011 + // No ZipArchive, fallback to WP's included PclZip + // .. we used to package our own copy of this, but it was flagging as malware. See GH-1011 - // proceed using pclzip - if ( class_exists('PclZip')){ + // proceed using pclzip + if ( class_exists( 'PclZip' ) ) { - try { + try { - if (file_exists($filepath) && file_exists($expandTo)){ + if ( file_exists( $filepath ) && file_exists( $expandTo ) ) { $archive = new PclZip( $filepath ); // @phan-suppress-next-line PhanParamTooMany -- PclZip functions use func_get_args. @@ -613,37 +602,32 @@ function zeroBSCRM_expandArchive($filepath,$expandTo){ } else { return true; } - } - - } catch (Exception $ex){ - - } + } catch ( Exception $ex ) { } - } - - return false; - } + return false; +} + /** * Wrapper for WP's built-in get_avatar(), but forces avatar display * whether or not "Show Avatar" WP setting is enabled. - * + * * Also adds the user display name as the alt if no alt is provided. */ - function jpcrm_get_avatar( $user_id, $size, $default='', $alt='', $args=array() ) { - if ( empty( $alt) ) { - $user = get_userdata( $user_id ); - if ($user) { - $alt = $user->display_name; - } +function jpcrm_get_avatar( $user_id, $size, $default = '', $alt = '', $args = array() ) { + if ( empty( $alt ) ) { + $user = get_userdata( $user_id ); + if ( $user ) { + $alt = $user->display_name; } - $args['force_display'] = true; - return get_avatar( $user_id, $size, $default, $alt, $args ); } + $args['force_display'] = true; + return get_avatar( $user_id, $size, $default, $alt, $args ); +} /** * Inject contacts as desired @@ -688,69 +672,70 @@ function jpcrm_inject_contacts( $contacts, $args ) { return $contacts; } - function zeroBSCRM_getGravatarURLfromEmail($email='',$size=80){ +function zeroBSCRM_getGravatarURLfromEmail( $email = '', $size = 80 ) { - // https: - $url = '//www.gravatar.com/avatar/' . hash( 'sha256', $email ); - $url = add_query_arg( array( + // https: + $url = '//www.gravatar.com/avatar/' . hash( 'sha256', $email ); + $url = add_query_arg( + array( 's' => $size, 'd' => 'mm', - ), $url ); - return esc_url_raw( $url ); - } + ), + $url + ); + return esc_url_raw( $url ); +} /* * Returns html to render business logo, if one is set in biz info settings */ - function jpcrm_business_logo_img( $max_width = '200px' ) { +function jpcrm_business_logo_img( $max_width = '200px' ) { - // got url? - $logo_url = jpcrm_business_logo_url(); + // got url? + $logo_url = jpcrm_business_logo_url(); - // if default, build html - if ( !empty( $logo_url ) ){ - return '' . esc_attr( zeroBSCRM_getSetting( 'businessname' ) ) . ''; - } - - return ''; + // if default, build html + if ( ! empty( $logo_url ) ) { + return '' . esc_attr( zeroBSCRM_getSetting( 'businessname' ) ) . ''; } + return ''; +} + /* * Returns an URL for business logo, if one is set in biz info settings * * For now is semi-redundant, but centralising for later expansion * */ - function jpcrm_business_logo_url( ) { - - // got url? - $logo_url = zeroBSCRM_getSetting( 'invoicelogourl' ); +function jpcrm_business_logo_url() { - // check default - if ( !empty( $logo_url ) ){ - return $logo_url; - } + // got url? + $logo_url = zeroBSCRM_getSetting( 'invoicelogourl' ); - return ''; + // check default + if ( ! empty( $logo_url ) ) { + return $logo_url; } - function zeroBSCRM_prettyformatBytes($size, $precision = 2){ - $base = log($size, 1024); - $suffixes = array('', 'K', 'M', 'G', 'T'); - - return round(pow(1024, $base - floor($base)), $precision) .''. $suffixes[floor($base)]; - } + return ''; +} - /* - * Split a Camel caps string (e.g. ThisStringBecomes = This String Becomes) - */ - function jpcrm_string_split_at_caps( $str ){ +function zeroBSCRM_prettyformatBytes( $size, $precision = 2 ) { + $base = log( $size, 1024 ); + $suffixes = array( '', 'K', 'M', 'G', 'T' ); - $parts = preg_split('/(?=[A-Z])/', $str); - return implode(' ', $parts); + return round( pow( 1024, $base - floor( $base ) ), $precision ) . '' . $suffixes[ floor( $base ) ]; +} - } + /* + * Split a Camel caps string (e.g. ThisStringBecomes = This String Becomes) + */ +function jpcrm_string_split_at_caps( $str ) { + $parts = preg_split( '/(?=[A-Z])/', $str ); + return implode( ' ', $parts ); +} /** * Returns send-from email + name @@ -776,64 +761,66 @@ function zeroBSCRM_wp_retrieveSendFrom() { ); } - - #} This'll be true if wl - function zeroBSCRM_isWL(){ - - ##WLREMOVE - return false; - ##/WLREMOVE - return true; - - } +function zeroBSCRM_isWL() { + ##WLREMOVE + return false; + ##/WLREMOVE + return true; +} // ============= TELEMETRY SECTION - // https://wordpress.stackexchange.com/questions/52144/what-wordpress-api-function-lists-active-inactive-plugins - function zeroBSCRM_allPluginListSimple() { - $plugins = get_plugins(); - $p = array(); - if (count($plugins) > 0) { - foreach ( $plugins as $plugin ) { - - $p[] = array('n' => $plugin['Name'],'v' => $plugin['Version']); - - } - } +function zeroBSCRM_allPluginListSimple() { + $plugins = get_plugins(); + $p = array(); + if ( count( $plugins ) > 0 ) { + foreach ( $plugins as $plugin ) { + + $p[] = array( + 'n' => $plugin['Name'], + 'v' => $plugin['Version'], + ); - return $p; - } + } + } - // this ver gets ONLY active - function zeroBSCRM_activePluginListSimple(){ - $pluginsActive = get_option('active_plugins'); - $plugins = get_plugins(); - $p = array(); - if (count($plugins) > 0) { - foreach ( $plugins as $pluginKey => $plugin ) { + return $p; +} - if (in_array($pluginKey,$pluginsActive)) $p[] = array('n' => $plugin['Name'],'v' => $plugin['Version']); + // this ver gets ONLY active +function zeroBSCRM_activePluginListSimple() { + $pluginsActive = get_option( 'active_plugins' ); + $plugins = get_plugins(); + $p = array(); + if ( count( $plugins ) > 0 ) { + foreach ( $plugins as $pluginKey => $plugin ) { + + if ( in_array( $pluginKey, $pluginsActive ) ) { + $p[] = array( + 'n' => $plugin['Name'], + 'v' => $plugin['Version'], + ); + } + } + } - } - } - - return $p; - } + return $p; +} // ============= / TELEMETRY SECTION - #} ZBS JSONP decode // https://stackoverflow.com/questions/5081557/extract-jsonp-resultset-in-php - function zeroBSCRM_jsonp_decode($jsonp, $assoc = false) { // PHP 5.3 adds depth as third parameter to json_decode - if($jsonp[0] !== '[' && $jsonp[0] !== '{') { // we have JSONP - $jsonp = substr($jsonp, strpos($jsonp, '(')); - } - return json_decode(trim($jsonp,'();'), $assoc); +function zeroBSCRM_jsonp_decode( $jsonp, $assoc = false ) { + // PHP 5.3 adds depth as third parameter to json_decode + if ( $jsonp[0] !== '[' && $jsonp[0] !== '{' ) { // we have JSONP + $jsonp = substr( $jsonp, strpos( $jsonp, '(' ) ); } + return json_decode( trim( $jsonp, '();' ), $assoc ); +} // used by DAL2 settings // https://stackoverflow.com/questions/6041741/fastest-way-to-check-if-a-string-is-json-in-php @@ -847,200 +834,192 @@ function zeroBSCRM_isJson( $str ) { } // return placeholder img :) DAL2 friendly - function zeroBSCRM_getDefaultContactAvatar(){ +function zeroBSCRM_getDefaultContactAvatar() { - // hmm - how to pass an img here? when using for html - // for now made a quick png - return plugins_url('/i/default-contact.png',ZBS_ROOTFILE); - - } + // hmm - how to pass an img here? when using for html + // for now made a quick png + return plugins_url( '/i/default-contact.png', ZBS_ROOTFILE ); +} // return logo - function jpcrm_get_logo( $stacked=true, $color='black' ){ - $logo_url = plugins_url( '/i/icon-32.png', ZBS_ROOTFILE ); - ##WLREMOVE - $logo_url = plugins_url( '/i/jpcrm-logo-'.($stacked?'stacked':'horizontal').'-'.$color.'.png', ZBS_ROOTFILE ); - ##/WLREMOVE - return $logo_url; - - } +function jpcrm_get_logo( $stacked = true, $color = 'black' ) { + $logo_url = plugins_url( '/i/icon-32.png', ZBS_ROOTFILE ); + ##WLREMOVE + $logo_url = plugins_url( '/i/jpcrm-logo-' . ( $stacked ? 'stacked' : 'horizontal' ) . '-' . $color . '.png', ZBS_ROOTFILE ); + ##/WLREMOVE + return $logo_url; +} // return placeholder img :) DAL2 friendly - function zeroBSCRM_getDefaultContactAvatarHTML(){ +function zeroBSCRM_getDefaultContactAvatarHTML() { - return ''; - - } + return ''; +} // https://stackoverflow.com/questions/2524680/check-whether-the-string-is-a-unix-timestamp - function zeroBSCRM_isValidTimeStamp($timestamp){ - return ((string) (int) $timestamp === $timestamp) - && ($timestamp <= PHP_INT_MAX) - && ($timestamp >= ~PHP_INT_MAX); - } +function zeroBSCRM_isValidTimeStamp( $timestamp ) { + return ( (string) (int) $timestamp === $timestamp ) + && ( $timestamp <= PHP_INT_MAX ) + && ( $timestamp >= ~PHP_INT_MAX ); +} // for use with export as per: // because of SYLK bug in excel, we have to wrap these in "" - but fputcsv doesnt do it :/ // https://www.alunr.com/excel-csv-import-returns-an-sylk-file-format-error/ // https://stackoverflow.com/questions/2489553/forcing-fputcsv-to-use-enclosure-for-all-fields - function zeroBSCRM_encloseArrItems($arr=array(),$encloseWith='"'){ +function zeroBSCRM_encloseArrItems( $arr = array(), $encloseWith = '"' ) { - $endArr = $arr; + $endArr = $arr; - if (is_array($arr)){ - - $endArr = array(); - foreach ($arr as $k => $v){ - $endArr[$k] = $encloseWith.$v.$encloseWith; - } + if ( is_array( $arr ) ) { + $endArr = array(); + foreach ( $arr as $k => $v ) { + $endArr[ $k ] = $encloseWith . $v . $encloseWith; } - - return $endArr; } + return $endArr; +} + // returns a filetype img if avail // returns 48px from https://github.com/redbooth/free-file-icons // ... cpp has fullsize 512px variants, but NOT to be added to core, adds bloat - function zeroBSCRM_fileTypeImg($fileExtension=''){ - - $fileExtension = sanitize_text_field( $fileExtension ); - if (!empty($fileExtension) && file_exists(ZEROBSCRM_PATH.'i/filetypes/'.$fileExtension.'.png')) return ZEROBSCRM_URL.'i/filetypes/'.$fileExtension.'.png'; - - return ZEROBSCRM_URL.'i/filetypes/_blank.png'; +function zeroBSCRM_fileTypeImg( $fileExtension = '' ) { + $fileExtension = sanitize_text_field( $fileExtension ); + if ( ! empty( $fileExtension ) && file_exists( ZEROBSCRM_PATH . 'i/filetypes/' . $fileExtension . '.png' ) ) { + return ZEROBSCRM_URL . 'i/filetypes/' . $fileExtension . '.png'; } + return ZEROBSCRM_URL . 'i/filetypes/_blank.png'; +} + // https://stackoverflow.com/questions/3797239/insert-new-item-in-array-on-any-position-in-php /** * @param array $array * @param int|string $position * @param mixed $insert */ - function zeroBSCRM_array_insert(&$array, $position, $insert) - { - if (is_int($position)) { - array_splice($array, $position, 0, $insert); - } else { - $pos = array_search($position, array_keys($array)); - $array = array_merge( - array_slice($array, 0, $pos), - $insert, - array_slice($array, $pos) - ); - } +function zeroBSCRM_array_insert( &$array, $position, $insert ) { + if ( is_int( $position ) ) { + array_splice( $array, $position, 0, $insert ); + } else { + $pos = array_search( $position, array_keys( $array ) ); + $array = array_merge( + array_slice( $array, 0, $pos ), + $insert, + array_slice( $array, $pos ) + ); } +} // WH ver of zeroBSCRM_array_insert, specifically used for messing with menu arrs (used mc2) - function zeroBSCRM_array_insert_ifset(&$array, $position, $insert){ - - // check for $position legitimacy - if (is_int($position)) { - - if (count($array) > $position) - return zeroBSCRM_array_insert($array,$position,$insert); - else { - // just add - $array = array_merge($array,$insert); - return $array; - } - - - } else if (is_array($position)){ - - // array - checks for subvalues to find position - /* +function zeroBSCRM_array_insert_ifset( &$array, $position, $insert ) { - e.g. in this: + // check for $position legitimacy + if ( is_int( $position ) ) { + if ( count( $array ) > $position ) { + return zeroBSCRM_array_insert( $array, $position, $insert ); + } else { + // just add + $array = array_merge( $array, $insert ); + return $array; + } + } elseif ( is_array( $position ) ) { - Array - ( - [0] => Array - ( - [0] => Jetpack CRM - [1] => zbs_dash - [2] => zerobscrm-dash - [3] => Jetpack CRM User Dash - ) - - [1] => Array - ( - [0] => Contacts - [1] => admin_zerobs_view_customers - [2] => manage-customers - [3] => Contacts - ) - - [2] => Array - ( - [0] => Quotes - [1] => admin_zerobs_view_quotes - [2] => manage-quotes - [3] => Quotes - ) + // array - checks for subvalues to find position + /* + e.g. in this: - ... if you passed $position as: - array('1'=>'admin_zerobs_view_customers') + Array + ( + [0] => Array + ( + [0] => Jetpack CRM + [1] => zbs_dash + [2] => zerobscrm-dash + [3] => Jetpack CRM User Dash + ) - ... it'd insert before [1] + [1] => Array + ( + [0] => Contacts + [1] => admin_zerobs_view_customers + [2] => manage-customers + [3] => Contacts + ) - */ + [2] => Array + ( + [0] => Quotes + [1] => admin_zerobs_view_quotes + [2] => manage-quotes + [3] => Quotes + ) + ... if you passed $position as: - // brutal - $endPos = -1; $i = 0; - foreach ($array as $a){ - // match position? - foreach ($position as $k => $v){ - if ($a[$k] == $v){ + array('1'=>'admin_zerobs_view_customers') - // has an attr matching position - $endPos = $i; - } - } + ... it'd insert before [1] - $i++; - } + */ - // should now have pos - if ($endPos > -1){ + // brutal + $endPos = -1; + $i = 0; + foreach ( $array as $a ) { + // match position? + foreach ( $position as $k => $v ) { + if ( $a[ $k ] == $v ) { - // probs str, fallback to - return zeroBSCRM_array_insert($array,$endPos,$insert); + // has an attr matching position + $endPos = $i; + } + } + ++$i; + } - } else { + // should now have pos + if ( $endPos > -1 ) { - // append - $array = array_merge($array,$insert); - return $array; + // probs str, fallback to + return zeroBSCRM_array_insert( $array, $endPos, $insert ); - } + } else { - } else { + // append + $array = array_merge( $array, $insert ); + return $array; - // probs str, fallback to - return zeroBSCRM_array_insert($array,$position,$insert); + } + } else { - } + // probs str, fallback to + return zeroBSCRM_array_insert( $array, $position, $insert ); } +} // simplistic directory empty check - function zeroBSCRM_is_dir_empty($dir) { - if (!is_readable($dir)) return null; - $handle = opendir($dir); - while (false !== ($entry = readdir($handle))) { - if ($entry !== '.' && $entry !== '..') { - closedir($handle); - return false; - } - } - closedir($handle); - return true; +function zeroBSCRM_is_dir_empty( $dir ) { + if ( ! is_readable( $dir ) ) { + return null; + } + $handle = opendir( $dir ); + while ( false !== ( $entry = readdir( $handle ) ) ) { + if ( $entry !== '.' && $entry !== '..' ) { + closedir( $handle ); + return false; + } } + closedir( $handle ); + return true; +} /** * Copyright © 2020 Theodore R. Smith @@ -1053,236 +1032,238 @@ function zeroBSCRM_is_dir_empty($dir) { * @param array $filtered Default: [., ..] * @return array */ - function jpcrm_get_directories($path, $recursive = false, array $filtered = []){ - if (!is_dir($path)) { - throw new RuntimeException("$path does not exist."); - } - - $filtered += ['.', '..']; +function jpcrm_get_directories( $path, $recursive = false, array $filtered = array() ) { + if ( ! is_dir( $path ) ) { + throw new RuntimeException( "$path does not exist." ); + } - $dirs = []; - $d = dir($path); - while (($entry = $d->read()) !== false) { - if (is_dir("$path/$entry") && !in_array($entry, $filtered)) { - $dirs[] = $entry; + $filtered += array( '.', '..' ); - if ($recursive) { - $newDirs = getDirs("$path/$entry"); - foreach ($newDirs as $newDir) { - $dirs[] = "$entry/$newDir"; - } - } - } - } + $dirs = array(); + $d = dir( $path ); + while ( ( $entry = $d->read() ) !== false ) { + if ( is_dir( "$path/$entry" ) && ! in_array( $entry, $filtered ) ) { + $dirs[] = $entry; - return $dirs; + if ( $recursive ) { + $newDirs = getDirs( "$path/$entry" ); + foreach ( $newDirs as $newDir ) { + $dirs[] = "$entry/$newDir"; + } + } + } } + return $dirs; +} - /** - * Takes an URL string and returns any $_GET parameters as an array - */ - function jpcrm_url_get_params( $url = '' ){ - - $components = parse_url($url); - if ( isset( $components['query'] ) ){ + /** + * Takes an URL string and returns any $_GET parameters as an array + */ +function jpcrm_url_get_params( $url = '' ) { - parse_str($components['query'], $results); - return $results; - - } + $components = parse_url( $url ); + if ( isset( $components['query'] ) ) { - return false; + parse_str( $components['query'], $results ); + return $results; } - - /** - * Returns bool whether or not an url has params - */ - function jpcrm_url_has_params( $url = '' ){ + return false; +} + + /** + * Returns bool whether or not an url has params + */ +function jpcrm_url_has_params( $url = '' ) { + + $components = parse_url( $url ); + if ( isset( $components['query'] ) ) { - $components = parse_url($url); - if ( isset( $components['query'] ) ){ - - parse_str($components['query'], $results); - - if ( count( $results ) > 0 ){ - - return true; + parse_str( $components['query'], $results ); - } - } + if ( count( $results ) > 0 ) { - return false; + return true; + } } + return false; +} /* * This is adapted from https://github.com/dompdf/dompdf/blob/master/src/Options.php#L1147-L1159 * ... to allow us to filter out non-site-url image injections */ - function jpcrm_dompdf_assist_validate_remote_uri( string $uri ){ +function jpcrm_dompdf_assist_validate_remote_uri( string $uri ) { if ( strlen( $uri ) === 0 ) { - return [false, "The URI must not be empty."]; - - } - - /* - if ( !$this->isRemoteEnabled ) { + return array( false, 'The URI must not be empty.' ); - return [false, "Remote file requested, but remote file download is disabled."]; + } - } - */ + /* + if ( !$this->isRemoteEnabled ) { - if ( !jpcrm_url_appears_to_match_site( $uri ) ){ + return [false, "Remote file requested, but remote file download is disabled."]; - return [false, "Remote file requested, but remote file download is disabled."]; + } + */ - } + if ( ! jpcrm_url_appears_to_match_site( $uri ) ) { + return array( false, 'Remote file requested, but remote file download is disabled.' ); - return [true, null]; } + return array( true, null ); +} -/* ====================================================== - / Globally useful generic Funcs - ====================================================== */ +/* +====================================================== + / Globally useful generic Funcs + ====================================================== */ -/* ====================================================== - unsub creation stuff - can't go in other as that's optionally included, - // migrations sometimes need to use pre-inclusion, so here for now #notidealbutokay - ====================================================== */ +/* +====================================================== + unsub creation stuff - can't go in other as that's optionally included, + // migrations sometimes need to use pre-inclusion, so here for now #notidealbutokay + ====================================================== */ // this is fired by a migration, and checked on deactivate ext -function zeroBSCRM_unsub_checkCreatePage(){ +function zeroBSCRM_unsub_checkCreatePage() { global $zbs; - //check if the page exists, if not create and call it clients + // check if the page exists, if not create and call it clients $pageID = zeroBSCRM_mail_getUnsubscribePage(); - if (empty($pageID) || $pageID < 1){ + if ( empty( $pageID ) || $pageID < 1 ) { // wh added to stop weird multi-fires (moving to migration fixed, but this is double protection) - if (!defined('ZBS_UNSUB_PAGE_MADE')){ + if ( ! defined( 'ZBS_UNSUB_PAGE_MADE' ) ) { - - //then we do not have a page for the client portal, create one, with slug clients and set as page - //this should handle any backwards compatibility and not lose the URLs created + // then we do not have a page for the client portal, create one, with slug clients and set as page + // this should handle any backwards compatibility and not lose the URLs created $args = array( - 'post_name' => 'unsubscribe', - 'post_status' => 'publish', - 'post_title' => __('Unsubscribed','zero-bs-crm'), + 'post_name' => 'unsubscribe', + 'post_status' => 'publish', + 'post_title' => __( 'Unsubscribed', 'zero-bs-crm' ), 'post_content' => '[jetpackcrm_unsubscribe]', - 'post_type' => 'page' + 'post_type' => 'page', ); - $pageID = wp_insert_post($args); - $zbs->settings->update('unsubpage', $pageID); - define('ZBS_UNSUB_PAGE_MADE',1); + $pageID = wp_insert_post( $args ); + $zbs->settings->update( 'unsubpage', $pageID ); + define( 'ZBS_UNSUB_PAGE_MADE', 1 ); return $pageID; } - - } else return $pageID; + } else { + return $pageID; + } return -1; } // returns an active page id or -1 -function zeroBSCRM_mail_getUnsubscribePage(){ +function zeroBSCRM_mail_getUnsubscribePage() { // what settings says it is - $pageID = (int)zeroBSCRM_getSetting('unsubpage'); + $pageID = (int) zeroBSCRM_getSetting( 'unsubpage' ); // is page live? - if (!empty($pageID) || $pageID > 0) { + if ( ! empty( $pageID ) || $pageID > 0 ) { - $pageStatus = get_post_status($pageID); - // page is trashed or smt, recreate - if ($pageStatus !== 'publish') $pageID = -1; - - } else $pageID = -1; + $pageStatus = get_post_status( $pageID ); + // page is trashed or smt, recreate + if ( $pageStatus !== 'publish' ) { + $pageID = -1; + } + } else { + $pageID = -1; + } return $pageID; } -/* ====================================================== - / unsub creation stuff - ====================================================== */ - +/* +====================================================== + / unsub creation stuff + ====================================================== */ -/* ====================================================== - Portal creation stuff - can't go in .Portal.php as that's optionally included, - // migrations sometimes need to use pre-inclusion, so here for now #notidealbutokay - ====================================================== */ +/* +====================================================== + Portal creation stuff - can't go in .Portal.php as that's optionally included, + // migrations sometimes need to use pre-inclusion, so here for now #notidealbutokay + ====================================================== */ // this is fired by a migration, and checked on deactivate ext -function zeroBSCRM_portal_checkCreatePage(){ +function zeroBSCRM_portal_checkCreatePage() { global $zbs; - //check if the page exists, if not create and call it clients + // check if the page exists, if not create and call it clients $portalPage = zeroBSCRM_portal_getPortalPage(); - if (empty($portalPage) || $portalPage < 1){ + if ( empty( $portalPage ) || $portalPage < 1 ) { // wh added to stop weird multi-fires (moving to migration fixed, but this is double protection) - if (!defined('ZBS_PORTAL_PAGE_MADE')){ + if ( ! defined( 'ZBS_PORTAL_PAGE_MADE' ) ) { - - //then we do not have a page for the client portal, create one, with slug clients and set as page - //this should handle any backwards compatibility and not lose the URLs created + // then we do not have a page for the client portal, create one, with slug clients and set as page + // this should handle any backwards compatibility and not lose the URLs created $args = array( - 'post_name' => 'clients', - 'post_status' => 'publish', - 'post_title' => __('Client Portal','zero-bs-crm'), + 'post_name' => 'clients', + 'post_status' => 'publish', + 'post_title' => __( 'Client Portal', 'zero-bs-crm' ), 'post_content' => '[jetpackcrm_clientportal]', - 'post_type' => 'page' + 'post_type' => 'page', ); - $portalID = wp_insert_post($args); - $zbs->settings->update('portalpage', $portalID); - define('ZBS_PORTAL_PAGE_MADE',1); + $portalID = wp_insert_post( $args ); + $zbs->settings->update( 'portalpage', $portalID ); + define( 'ZBS_PORTAL_PAGE_MADE', 1 ); return $portalID; } - - } else return $portalPage; + } else { + return $portalPage; + } return -1; } // returns an active page id or -1 -function zeroBSCRM_portal_getPortalPage(){ +function zeroBSCRM_portal_getPortalPage() { // what settings says it is - $portalPage = (int)zeroBSCRM_getSetting('portalpage'); + $portalPage = (int) zeroBSCRM_getSetting( 'portalpage' ); // is page live? - if (!empty($portalPage) || $portalPage > 0) { + if ( ! empty( $portalPage ) || $portalPage > 0 ) { - $pageStatus = get_post_status($portalPage); - // page is trashed or smt, recreate - if ($pageStatus !== 'publish') $portalPage = -1; - - } else $portalPage = -1; + $pageStatus = get_post_status( $portalPage ); + // page is trashed or smt, recreate + if ( $pageStatus !== 'publish' ) { + $portalPage = -1; + } + } else { + $portalPage = -1; + } return $portalPage; } -/* ====================================================== - / Portal creation stuff - ====================================================== */ - - +/* +====================================================== + / Portal creation stuff + ====================================================== */ -/* ====================================================== - Link Helpers - ====================================================== */ +/* +====================================================== + Link Helpers + ====================================================== */ // produces a portal based link to a potentially-hashed obj (inv/quo as of v3.0) function zeroBSCRM_portal_linkObj( $obj_id = -1, $type_int = ZBS_TYPE_INVOICE ) { global $zbs; @@ -1300,25 +1281,25 @@ function zeroBSCRM_portal_linkObj( $obj_id = -1, $type_int = ZBS_TYPE_INVOICE ) if ( $use_hash == '1' ) { $hash = $zbs->DAL->invoices->getInvoiceHash( $obj_id ); if ( ! empty( $hash ) ) { - return esc_url( $portal_base_url . $invoices_endpoint . $url_separator .'zh-' . $hash ); + return esc_url( $portal_base_url . $invoices_endpoint . $url_separator . 'zh-' . $hash ); } } return esc_url( $portal_base_url . $invoices_endpoint . $url_separator . $obj_id ); break; case ZBS_TYPE_QUOTE: - // get quotes stem - $quotes_endpoint = $zbs->modules->portal->get_endpoint( ZBS_TYPE_QUOTE ); + // get quotes stem + $quotes_endpoint = $zbs->modules->portal->get_endpoint( ZBS_TYPE_QUOTE ); // got hash? - if ( $use_hash == "1" ) { - $hash = $zbs->DAL->quotes->getQuoteHash($obj_id); + if ( $use_hash == '1' ) { + $hash = $zbs->DAL->quotes->getQuoteHash( $obj_id ); if ( ! empty( $hash ) ) { - return esc_url( $portal_base_url . $quotes_endpoint . $url_separator . 'zh-' . $hash ); + return esc_url( $portal_base_url . $quotes_endpoint . $url_separator . 'zh-' . $hash ); } } // otherwise just id - return esc_url( $portal_base_url . $quotes_endpoint . $url_separator . $obj_id ); + return esc_url( $portal_base_url . $quotes_endpoint . $url_separator . $obj_id ); break; } } @@ -1327,8 +1308,8 @@ function jpcrm_get_portal_slug() { $portal_page_id = zeroBSCRM_getSetting( 'portalpage' ); $portal_post = get_post( $portal_page_id ); $portal_permalink = $portal_post ? rtrim( _get_page_link( $portal_post ), '/' ) : ''; - $portal_slug = str_replace( home_url(), "", $portal_permalink); - + $portal_slug = str_replace( home_url(), '', $portal_permalink ); + if ( empty( $portal_slug ) ) { $portal_slug = 'clients'; } @@ -1337,15 +1318,15 @@ function jpcrm_get_portal_slug() { } function jpcrm_get_client_portal_root_url() { - $client_portal_root_url = home_url( jpcrm_get_portal_slug() ); + $client_portal_root_url = home_url( jpcrm_get_portal_slug() ); // The url separator should be '&' when plain permalinks are being used $client_portal_root_url .= ( ! str_contains( $client_portal_root_url, '?' ) ) ? '/' : '&'; return $client_portal_root_url; } -function zeroBS_portal_link($type='dash',$objIDorHashStr=-1){ - $portalPage = zeroBSCRM_getSetting('portalpage'); +function zeroBS_portal_link( $type = 'dash', $objIDorHashStr = -1 ) { + $portalPage = zeroBSCRM_getSetting( 'portalpage' ); $portalLink = jpcrm_get_client_portal_root_url(); $portalSlug = jpcrm_get_portal_slug(); @@ -1358,45 +1339,47 @@ function zeroBS_portal_link($type='dash',$objIDorHashStr=-1){ break; default: + // catch generic e.g. quotes invoices - // catch generic e.g. quotes invoices - - $stem = $type; //'quotes'; + $stem = $type; // 'quotes'; // if cpp, use that stem - if (function_exists('zeroBSCRM_clientPortalgetEndpoint')) $stem = zeroBSCRM_clientPortalgetEndpoint($stem); + if ( function_exists( 'zeroBSCRM_clientPortalgetEndpoint' ) ) { + $stem = zeroBSCRM_clientPortalgetEndpoint( $stem ); + } // if using a str (hash) then prefix with zh- if not already - if (is_string($objIDorHashStr)){ + if ( is_string( $objIDorHashStr ) ) { if ( ! str_starts_with( $objIDorHashStr, 'zh-' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $objIDorHashStr = 'zh-' . $objIDorHashStr; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } } if ( - (!is_string($objIDorHashStr) && ($objIDorHashStr == -1 || $objIDorHashStr <= 0)) // is false ID + ( ! is_string( $objIDorHashStr ) && ( $objIDorHashStr == -1 || $objIDorHashStr <= 0 ) ) // is false ID || - (is_string($objIDorHashStr) && empty($objIDorHashStr)) // is empty hash str - ) - return home_url('/'.$portalSlug.'/'.$stem.'/'); - else - return home_url('/'.$portalSlug.'/'.$stem.'/'.$objIDorHashStr); + ( is_string( $objIDorHashStr ) && empty( $objIDorHashStr ) ) // is empty hash str + ) { + return home_url( '/' . $portalSlug . '/' . $stem . '/' ); + } else { + return home_url( '/' . $portalSlug . '/' . $stem . '/' . $objIDorHashStr ); + } break; - } - return home_url('/#notfound'); + return home_url( '/#notfound' ); } -/* ====================================================== - / Link Helpers - ====================================================== */ - +/* +====================================================== + / Link Helpers + ====================================================== */ -/* ====================================================== - General WP Helpers - ====================================================== */ +/* +====================================================== + General WP Helpers + ====================================================== */ /* * Compares the version of WordPress running to the $version specified. @@ -1410,22 +1393,22 @@ function jpcrm_wordpress_version( $operator = '>', $version = '4.0' ) { return version_compare( $wp_version, $version, $operator ); } -/* ====================================================== - / General WP Helpers - ====================================================== */ - - +/* +====================================================== + / General WP Helpers + ====================================================== */ -/* ====================================================== - Security Helpers - ====================================================== */ +/* +====================================================== + Security Helpers + ====================================================== */ /** * Adds .htaccess and index.html files to directory * Used to block access to those which we don't want externally accessible * If the directory does not exist, creates it - * - * Adapted from Woo's ReportCSVExporter->maybe_create_directory() + * + * Adapted from Woo's ReportCSVExporter->maybe_create_directory() * https://github.com/Automattic/woocommerce-admin/pull/6/files#diff-93130caa7eb757181d642767bfcd229f7e1124d0348d05f8db48f432df44fb62R70 * * @param $directory_path - full path to directory @@ -1477,65 +1460,65 @@ function jpcrm_create_and_secure_dir_from_external_access( $directory_path = '', fclose( $file_handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose } - if ( ! file_exists( trailingslashit( $file['base'] ) . $file['file'] ) ){ + if ( ! file_exists( trailingslashit( $file['base'] ) . $file['file'] ) ) { // failed to create file $safe = false; - - } + } } - } return $safe; - } -/* ====================================================== - / Security Helpers - ====================================================== */ +/* +====================================================== + / Security Helpers + ====================================================== */ -/* ====================================================== - Dashboard Helpers - ====================================================== */ +/* +====================================================== + Dashboard Helpers + ====================================================== */ /* * Returns arrays of zeros (for dashboard graph prep) */ -function jetpackcrm_create_zeros_array($start, $end, $zbs_steps = 86400){ +function jetpackcrm_create_zeros_array( $start, $end, $zbs_steps = 86400 ) { $filled_zeros_y = array(); $filled_zeros_m = array(); $filled_zeros_w = array(); $filled_zeros_d = array(); $the_day = $start; - while($the_day <= $end){ - $the_year= date("Y", $the_day); - $filled_zeros_y[$the_year] = 0; + while ( $the_day <= $end ) { + $the_year = date( 'Y', $the_day ); + $filled_zeros_y[ $the_year ] = 0; - $the_month = date("M y", $the_day); - $filled_zeros_m[$the_month] = 0; + $the_month = date( 'M y', $the_day ); + $filled_zeros_m[ $the_month ] = 0; - $the_week = date("W Y", $the_day); - $filled_zeros_w[$the_week] = 0; + $the_week = date( 'W Y', $the_day ); + $filled_zeros_w[ $the_week ] = 0; - $the_day_d = date("d M y", $the_day); - $filled_zeros_d[$the_day_d] = 0; + $the_day_d = date( 'd M y', $the_day ); + $filled_zeros_d[ $the_day_d ] = 0; $the_day += $zbs_steps; } - $filled_zeros['year'] = $filled_zeros_y; + $filled_zeros['year'] = $filled_zeros_y; $filled_zeros['month'] = $filled_zeros_m; - $filled_zeros['week'] = $filled_zeros_w; - $filled_zeros['day'] = $filled_zeros_d; + $filled_zeros['week'] = $filled_zeros_w; + $filled_zeros['day'] = $filled_zeros_d; return $filled_zeros; } -/* ====================================================== - / Dashboard Helpers - ====================================================== */ +/* +====================================================== + / Dashboard Helpers + ====================================================== */ /* * Returns a YouTube thumbnail URL of a video @@ -1544,20 +1527,18 @@ function jetpackcrm_create_zeros_array($start, $end, $zbs_steps = 86400){ * @param string $quality (sd|mq|hq|maxres) * @returns string|boolean */ -function jpcrm_youtube_url_to_thumbnail_url( $video_url, $quality = 'mq' ){ +function jpcrm_youtube_url_to_thumbnail_url( $video_url, $quality = 'mq' ) { $video_id = jpcrm_youtube_url_to_video_id( $video_url ); - if ( !empty( $video_id ) ){ + if ( ! empty( $video_id ) ) { return 'http://img.youtube.com/vi/' . $video_id . '/' . $quality . 'default.jpg'; } return false; - } - /* * Returns a YouTube video ID of a video * @@ -1566,23 +1547,22 @@ function jpcrm_youtube_url_to_thumbnail_url( $video_url, $quality = 'mq' ){ */ function jpcrm_youtube_url_to_video_id( $video_url ) { - $video_id = explode( "?v=", $video_url ); - if ( !isset( $video_id[1] ) ) { - $video_id = explode( "youtu.be/", $video_url ); - } - if ( empty($video_id[1]) ) { - $video_id = explode("/v/", $video_url); - } - if ( is_array( $video_id ) ){ - $video_id = explode( "&", $video_id[1] ); - $youtube_video_id = $video_id[0]; - if ( !empty( $youtube_video_id ) ) { - return $youtube_video_id; - } + $video_id = explode( '?v=', $video_url ); + if ( ! isset( $video_id[1] ) ) { + $video_id = explode( 'youtu.be/', $video_url ); + } + if ( empty( $video_id[1] ) ) { + $video_id = explode( '/v/', $video_url ); + } + if ( is_array( $video_id ) ) { + $video_id = explode( '&', $video_id[1] ); + $youtube_video_id = $video_id[0]; + if ( ! empty( $youtube_video_id ) ) { + return $youtube_video_id; + } } - return false; - + return false; } /** diff --git a/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomator.php b/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomator.php index 570dd9289f04..45ec27a52aa6 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomator.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomator.php @@ -1,5 +1,6 @@ -internalAutomatorBlock) $goodToGo = false; - + if ( $zbs->internalAutomatorBlock ) { + $goodToGo = false; + } - if ($goodToGo && !empty($actionStr)){ + if ( $goodToGo && ! empty( $actionStr ) ) { #} Action str should be alphanumeric with periods #} Checks if there's a global variable (work list) for this $actionStr - $actionHolderName = 'zeroBSCRM_IA_Action_'.str_replace('.','_',$actionStr); + $actionHolderName = 'zeroBSCRM_IA_Action_' . str_replace( '.', '_', $actionStr ); #} Exists? - if (isset($GLOBALS[ $actionHolderName ]) && is_array($GLOBALS[ $actionHolderName ])){ + if ( isset( $GLOBALS[ $actionHolderName ] ) && is_array( $GLOBALS[ $actionHolderName ] ) ) { - #} If here, has an array - foreach ($GLOBALS[ $actionHolderName ] as $action){ + #} If here, has an array + foreach ( $GLOBALS[ $actionHolderName ] as $action ) { - if (isset($action['act']) && !empty($action['act']) && isset($action['params'])){ + if ( isset( $action['act'] ) && ! empty( $action['act'] ) && isset( $action['params'] ) ) { #} ['params'] not used yet... future proofing. #} Fire any applicable - if (function_exists($action['act'])){ + if ( function_exists( $action['act'] ) ) { #} call it, (and pass whatever was passed to this) - - - call_user_func($action['act'],$obj); + call_user_func( $action['act'], $obj ); } - - } - } - } - } - return; - + return; } +function zeroBSCRM_AddInternalAutomatorRecipe( $actionStr = '', $functionName = '', $paramsObj = array() ) { -function zeroBSCRM_AddInternalAutomatorRecipe($actionStr='',$functionName='',$paramsObj=array()){ - - if (!empty($actionStr) && !empty($functionName)){ + if ( ! empty( $actionStr ) && ! empty( $functionName ) ) { #} Some legacy support - $actionStr = zeroBSCRM_InternalAutomatorLegacyActionCheck($actionStr); + $actionStr = zeroBSCRM_InternalAutomatorLegacyActionCheck( $actionStr ); #} Action str should be alphanumeric with periods #} Checks if there's a global variable (work list) for this $actionStr - $actionHolderName = 'zeroBSCRM_IA_Action_'.str_replace('.','_',$actionStr); + $actionHolderName = 'zeroBSCRM_IA_Action_' . str_replace( '.', '_', $actionStr ); #} Init? - if (!isset($GLOBALS[ $actionHolderName ])) $GLOBALS[ $actionHolderName ] = array(); + if ( ! isset( $GLOBALS[ $actionHolderName ] ) ) { + $GLOBALS[ $actionHolderName ] = array(); + } #} Append. - array_push($GLOBALS[ $actionHolderName ],array('act'=>$functionName,'params'=>$paramsObj)); + array_push( + $GLOBALS[ $actionHolderName ], + array( + 'act' => $functionName, + 'params' => $paramsObj, + ) + ); return true; @@ -140,10 +138,10 @@ function zeroBSCRM_AddInternalAutomatorRecipe($actionStr='',$functionName='',$pa } // checks for newer labels + converts -function zeroBSCRM_InternalAutomatorLegacyActionCheck($actionStr = ''){ - +function zeroBSCRM_InternalAutomatorLegacyActionCheck( $actionStr = '' ) { + #} Some legacy support - switch ($actionStr){ + switch ( $actionStr ) { case 'contact.new': $actionStr = 'customer.new'; @@ -158,9 +156,9 @@ function zeroBSCRM_InternalAutomatorLegacyActionCheck($actionStr = ''){ } return $actionStr; - } - -/* ====================================================== + +/* +====================================================== / Internal Automator - ====================================================== */ + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomatorRecipes.php b/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomatorRecipes.php index 4aaf5d7cd031..a8fef4e635fb 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomatorRecipes.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomatorRecipes.php @@ -1,5 +1,6 @@ - 0){ - - #} Retrieve necessary info: - $zbsNoteAgainstPostID = -1; if (is_array($obj) && isset($obj['id'])) $zbsNoteAgainstPostID = (int)$obj['id']; - if (isset($zbsNoteAgainstPostID) && !empty($zbsNoteAgainstPostID)){ - - #} First check if an override is passed... - if (isset($obj['automatorpassthrough']) && is_array($obj['automatorpassthrough']) && isset($obj['automatorpassthrough']['note_override']) && is_array($obj['automatorpassthrough']['note_override']) && isset($obj['automatorpassthrough']['note_override']['type'])){ - - #} An overriding note has been passed, just use that - - #} Add log - $newLogID = zeroBS_addUpdateContactLog($zbsNoteAgainstPostID,-1,-1,$obj['automatorpassthrough']['note_override']); - - } else { - - #} No override, use default processing... - - +function zeroBSCRM_IA_NewCustomerLog( $obj = array() ) { - #} Set Deets - $newCustomerName = ''; if (is_array($obj) && isset($obj['id']) && isset($obj['customerMeta']) && is_array($obj['customerMeta'])) $newCustomerName = zeroBS_customerName($obj['id'],$obj['customerMeta'],false,true); - $noteShortDesc = 'Customer Created'; if (!empty($newCustomerName)) $noteShortDesc = $newCustomerName; - $note_long_description = ''; + # if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_customer_new' ); - // Custom short desc for external source creations - if (isset($obj['extsource']) && !empty($obj['extsource'])){ + if ( $autoLogThis > 0 ) { - $uid = ''; + #} Retrieve necessary info: + $zbsNoteAgainstPostID = -1; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $zbsNoteAgainstPostID = (int) $obj['id']; + } + if ( isset( $zbsNoteAgainstPostID ) && ! empty( $zbsNoteAgainstPostID ) ) { - // We seem to pass either the external source array (woo) - // ... or a string 'pay', so lets select the right one... - if ( is_array( $obj['extsource'] ) && isset( $obj['extsource']['source'] ) ){ + #} First check if an override is passed... + if ( isset( $obj['automatorpassthrough'] ) && is_array( $obj['automatorpassthrough'] ) && isset( $obj['automatorpassthrough']['note_override'] ) && is_array( $obj['automatorpassthrough']['note_override'] ) && isset( $obj['automatorpassthrough']['note_override']['type'] ) ) { - $source_key = $obj['extsource']['source']; + #} An overriding note has been passed, just use that - // if we have this we also have UID - $uid = $obj['extsource']['uid']; + #} Add log + $newLogID = zeroBS_addUpdateContactLog( $zbsNoteAgainstPostID, -1, -1, $obj['automatorpassthrough']['note_override'] ); - } else { - $source_key = $obj['extsource']; - } + } else { - switch ( $source_key ){ + #} No override, use default processing... - case 'pay': + #} Set Deets + $newCustomerName = ''; + if ( is_array( $obj ) && isset( $obj['id'] ) && isset( $obj['customerMeta'] ) && is_array( $obj['customerMeta'] ) ) { + $newCustomerName = zeroBS_customerName( $obj['id'], $obj['customerMeta'], false, true ); + } + $noteShortDesc = 'Customer Created'; + if ( ! empty( $newCustomerName ) ) { + $noteShortDesc = $newCustomerName; + } + $note_long_description = ''; - $note_long_description = __( 'Created from PayPal', 'zero-bs-crm' ) . ''; + // Custom short desc for external source creations + if ( isset( $obj['extsource'] ) && ! empty( $obj['extsource'] ) ) { - break; + $uid = ''; - case 'woo': + // We seem to pass either the external source array (woo) + // ... or a string 'pay', so lets select the right one... + if ( is_array( $obj['extsource'] ) && isset( $obj['extsource']['source'] ) ) { - $note_long_description = __( 'Created from WooCommerce Order', 'zero-bs-crm' ) . ' '; + $source_key = $obj['extsource']['source']; - break; + // if we have this we also have UID + $uid = $obj['extsource']['uid']; - case 'env': + } else { + $source_key = $obj['extsource']; + } - $note_long_description = __( 'Created from Envato', 'zero-bs-crm' ) . ''; + switch ( $source_key ) { - break; + case 'pay': + $note_long_description = __( 'Created from PayPal', 'zero-bs-crm' ) . ''; - case 'form': + break; - $note_long_description = __( 'Created from Form Capture', 'zero-bs-crm' ) . ''; + case 'woo': + $note_long_description = __( 'Created from WooCommerce Order', 'zero-bs-crm' ) . ' '; - break; + break; - case 'csv': + case 'env': + $note_long_description = __( 'Created from Envato', 'zero-bs-crm' ) . ''; - $note_long_description = __( 'Created from CSV Import', 'zero-bs-crm' ) . ''; + break; - break; + case 'form': + $note_long_description = __( 'Created from Form Capture', 'zero-bs-crm' ) . ''; - case 'gra': + break; - $note_long_description = __( 'Created from Gravity Forms', 'zero-bs-crm' ) . ''; + case 'csv': + $note_long_description = __( 'Created from CSV Import', 'zero-bs-crm' ) . ''; - break; + break; - default: + case 'gra': + $note_long_description = __( 'Created from Gravity Forms', 'zero-bs-crm' ) . ''; - // Generic fallback (shouldn't ever fire) - $note_long_description = __( 'Created from External Source', 'zero-bs-crm' ) . ' '; + break; - break; + default: + // Generic fallback (shouldn't ever fire) + $note_long_description = __( 'Created from External Source', 'zero-bs-crm' ) . ' '; - } - - // allow extension override via filter (e.g. WooSync) - $note_long_description = apply_filters( 'jpcrm_new_contact_log', $note_long_description, $source_key, $uid ); + break; + } - } + // allow extension override via filter (e.g. WooSync) + $note_long_description = apply_filters( 'jpcrm_new_contact_log', $note_long_description, $source_key, $uid ); + } - #} Add log - $newLogID = zeroBS_addUpdateContactLog($zbsNoteAgainstPostID,-1,-1,array( - 'type' => 'Created', + #} Add log + $newLogID = zeroBS_addUpdateContactLog( + $zbsNoteAgainstPostID, + -1, + -1, + array( + 'type' => 'Created', 'shortdesc' => $noteShortDesc, - 'longdesc' => $note_long_description - )); - - } # / end of if no override + 'longdesc' => $note_long_description, + ) + ); - } + } # / end of if no override } - - } +} #} Adds a "created" log to users (if setting) - function zeroBSCRM_IA_NewCompanyLog($obj=array()){ - - # if setting - $autoLogThis = zeroBSCRM_getSetting('autolog_company_new'); - - if ($autoLogThis > 0){ - - #} Retrieve necessary info: - $zbsNoteAgainstPostID = -1; if (is_array($obj) && isset($obj['id'])) $zbsNoteAgainstPostID = (int)$obj['id']; - if (isset($zbsNoteAgainstPostID) && !empty($zbsNoteAgainstPostID)){ +function zeroBSCRM_IA_NewCompanyLog( $obj = array() ) { - #} First check if an override is passed... - if (isset($obj['automatorpassthrough']) && is_array($obj['automatorpassthrough']) && isset($obj['automatorpassthrough']['note_override']) && is_array($obj['automatorpassthrough']['note_override']) && isset($obj['automatorpassthrough']['note_override']['type'])){ + # if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_company_new' ); - #} An overriding note has been passed, just use that + if ( $autoLogThis > 0 ) { - #} Add log - $newLogID = zeroBS_addUpdateLog($zbsNoteAgainstPostID,-1,-1,$obj['automatorpassthrough']['note_override'],'zerobs_company'); - - } else { - - #} No override, use default processing... - - - - #} Set Deets - $newCompanyName = ''; if (is_array($obj) && isset($obj['id']) && isset($obj['companyMeta']) && is_array($obj['companyMeta'])) $newCompanyName = zeroBS_companyName($obj['id'],$obj['companyMeta'],false,true); - $noteShortDesc = 'Company Created'; if (!empty($newCompanyName)) $noteShortDesc = $newCompanyName; - $note_long_description = ''; - - // Custom short desc for external source creations - if (isset($obj['extsource']) && !empty($obj['extsource'])){ - - // We seem to pass either the external source array (woo) - // ... or a string 'pay', so lets select the right one... - if ( is_array( $obj['extsource'] ) && isset( $obj['extsource']['source'] ) ){ - - $source_key = $obj['extsource']['source']; + #} Retrieve necessary info: + $zbsNoteAgainstPostID = -1; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $zbsNoteAgainstPostID = (int) $obj['id']; + } + if ( isset( $zbsNoteAgainstPostID ) && ! empty( $zbsNoteAgainstPostID ) ) { - // if we have this we also have UID - $uid = $obj['extsource']['uid']; + #} First check if an override is passed... + if ( isset( $obj['automatorpassthrough'] ) && is_array( $obj['automatorpassthrough'] ) && isset( $obj['automatorpassthrough']['note_override'] ) && is_array( $obj['automatorpassthrough']['note_override'] ) && isset( $obj['automatorpassthrough']['note_override']['type'] ) ) { - } else { - $source_key = $obj['extsource']; - } + #} An overriding note has been passed, just use that - switch ( $source_key ){ + #} Add log + $newLogID = zeroBS_addUpdateLog( $zbsNoteAgainstPostID, -1, -1, $obj['automatorpassthrough']['note_override'], 'zerobs_company' ); - case 'pay': + } else { - $note_long_description = 'Created from PayPal '; + #} No override, use default processing... - break; + #} Set Deets + $newCompanyName = ''; + if ( is_array( $obj ) && isset( $obj['id'] ) && isset( $obj['companyMeta'] ) && is_array( $obj['companyMeta'] ) ) { + $newCompanyName = zeroBS_companyName( $obj['id'], $obj['companyMeta'], false, true ); + } + $noteShortDesc = 'Company Created'; + if ( ! empty( $newCompanyName ) ) { + $noteShortDesc = $newCompanyName; + } + $note_long_description = ''; - case 'woo': + // Custom short desc for external source creations + if ( isset( $obj['extsource'] ) && ! empty( $obj['extsource'] ) ) { - if ( isset( $uid ) ){ - $note_long_description = sprintf( __( 'Created from WooCommerce Order #%s', 'zero-bs-crm' ), $uid ) . ' '; - } else { - $note_long_description = __( 'Created from WooCommerce Order', 'zero-bs-crm' ) . ' '; - } + // We seem to pass either the external source array (woo) + // ... or a string 'pay', so lets select the right one... + if ( is_array( $obj['extsource'] ) && isset( $obj['extsource']['source'] ) ) { - break; + $source_key = $obj['extsource']['source']; - case 'env': + // if we have this we also have UID + $uid = $obj['extsource']['uid']; - $note_long_description = 'Created from Envato '; + } else { + $source_key = $obj['extsource']; + } - break; + switch ( $source_key ) { - case 'form': + case 'pay': + $note_long_description = 'Created from PayPal '; - $note_long_description = 'Created from Form Capture '; + break; - break; + case 'woo': + if ( isset( $uid ) ) { + $note_long_description = sprintf( __( 'Created from WooCommerce Order #%s', 'zero-bs-crm' ), $uid ) . ' '; + } else { + $note_long_description = __( 'Created from WooCommerce Order', 'zero-bs-crm' ) . ' '; + } - case 'csv': + break; - $note_long_description = 'Created from CSV Import '; + case 'env': + $note_long_description = 'Created from Envato '; - break; + break; - default: + case 'form': + $note_long_description = 'Created from Form Capture '; - #} Generic for now (SHOULD NEVER CALL) - $note_long_description = 'Created from External Source '; + break; - break; + case 'csv': + $note_long_description = 'Created from CSV Import '; - } + break; + default: + #} Generic for now (SHOULD NEVER CALL) + $note_long_description = 'Created from External Source '; - } + break; + } + } - #} Add log - $newLogID = zeroBS_addUpdateLog($zbsNoteAgainstPostID,-1,-1,array( - 'type' => 'Created', + #} Add log + $newLogID = zeroBS_addUpdateLog( + $zbsNoteAgainstPostID, + -1, + -1, + array( + 'type' => 'Created', 'shortdesc' => $noteShortDesc, - 'longdesc' => $note_long_description - ),'zerobs_company'); + 'longdesc' => $note_long_description, + ), + 'zerobs_company' + ); - } # / end of if no override - - } + } # / end of if no override } - - } +} #} Adds a "created" log to customer (of quotes) (if setting) - function zeroBSCRM_IA_NewQuoteLog($obj=array()){ - - - # if setting - $autoLogThis = zeroBSCRM_getSetting('autolog_quote_new'); - - if ($autoLogThis > 0){ +function zeroBSCRM_IA_NewQuoteLog( $obj = array() ) { - // 3.0+ - #} Retrieve necessary info: - $noteAgainstIDs = array('contacts'=>array(),'companies'=>array()); - if (is_array($obj) && isset($obj['againstids']) && is_array($obj['againstids'])){ + # if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_quote_new' ); - // trusting they're correctly passed... - if (isset($obj['againstids']['contacts']) && is_array($obj['againstids']['contacts'])) $noteAgainstIDs['contacts'] = $obj['againstids']['contacts']; - if (isset($obj['againstids']['companies']) && is_array($obj['againstids']['companies'])) $noteAgainstIDs['companies'] = $obj['againstids']['companies']; + if ( $autoLogThis > 0 ) { + // 3.0+ + #} Retrieve necessary info: + $noteAgainstIDs = array( + 'contacts' => array(), + 'companies' => array(), + ); + if ( is_array( $obj ) && isset( $obj['againstids'] ) && is_array( $obj['againstids'] ) ) { + + // trusting they're correctly passed... + if ( isset( $obj['againstids']['contacts'] ) && is_array( $obj['againstids']['contacts'] ) ) { + $noteAgainstIDs['contacts'] = $obj['againstids']['contacts']; } - $quoteID = ''; if (is_array($obj) && isset($obj['id'])) $quoteID = $obj['id']; - $quoteTitle = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['title']) && !empty($obj['data']['title'])) $quoteTitle = $obj['data']['title']; - $quoteValue = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['value']) && !empty($obj['data']['value'])) $quoteValue = zeroBSCRM_formatCurrency($obj['data']['value']); - $extsource = ''; if (is_array($obj) && is_array($obj['extsource']) && isset($obj['extsource']['source']) && !empty($obj['extsource']['source'])) $extsource = $obj['extsource']['source']; - $extsourceID = ''; if (is_array($obj) && is_array($obj['extsource']) && isset($obj['extsource']['uid']) && !empty($obj['extsource']['uid'])) $extsourceID = $obj['extsource']['uid']; - - // build str - $note_long_description = ''; - $noteShortDesc = ''; - if (!empty($quoteID)) $noteShortDesc .= '#'.$quoteID; - if (!empty($quoteTitle)) $noteShortDesc .= $quoteTitle; - if (!empty($quoteValue)) $noteShortDesc .= ' ('.$quoteValue.')'; - if (!empty($extsource) && !empty($extsourceID)) $note_long_description = __('Created by','zero-bs-crm').' '.zeroBS_getExternalSourceTitle($extsource,$extsourceID); + if ( isset( $obj['againstids']['companies'] ) && is_array( $obj['againstids']['companies'] ) ) { + $noteAgainstIDs['companies'] = $obj['againstids']['companies']; + } + } + $quoteID = ''; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $quoteID = $obj['id']; + } + $quoteTitle = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['title'] ) && ! empty( $obj['data']['title'] ) ) { + $quoteTitle = $obj['data']['title']; + } + $quoteValue = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['value'] ) && ! empty( $obj['data']['value'] ) ) { + $quoteValue = zeroBSCRM_formatCurrency( $obj['data']['value'] ); + } + $extsource = ''; + if ( is_array( $obj ) && is_array( $obj['extsource'] ) && isset( $obj['extsource']['source'] ) && ! empty( $obj['extsource']['source'] ) ) { + $extsource = $obj['extsource']['source']; + } + $extsourceID = ''; + if ( is_array( $obj ) && is_array( $obj['extsource'] ) && isset( $obj['extsource']['uid'] ) && ! empty( $obj['extsource']['uid'] ) ) { + $extsourceID = $obj['extsource']['uid']; + } - if (is_array($noteAgainstIDs['contacts']) && count($noteAgainstIDs['contacts']) > 0) foreach ($noteAgainstIDs['contacts'] as $cID){ + // build str + $note_long_description = ''; + $noteShortDesc = ''; + if ( ! empty( $quoteID ) ) { + $noteShortDesc .= '#' . $quoteID; + } + if ( ! empty( $quoteTitle ) ) { + $noteShortDesc .= $quoteTitle; + } + if ( ! empty( $quoteValue ) ) { + $noteShortDesc .= ' (' . $quoteValue . ')'; + } + if ( ! empty( $extsource ) && ! empty( $extsourceID ) ) { + $note_long_description = __( 'Created by', 'zero-bs-crm' ) . ' ' . zeroBS_getExternalSourceTitle( $extsource, $extsourceID ); + } + + if ( is_array( $noteAgainstIDs['contacts'] ) && count( $noteAgainstIDs['contacts'] ) > 0 ) { + foreach ( $noteAgainstIDs['contacts'] as $cID ) { #} Add log - $newLogID = zeroBS_addUpdateLog($cID,-1,-1,array( - 'type' => __('Quote Created','zero-bs-crm'), - 'shortdesc' => $noteShortDesc, - 'longdesc' => $note_long_description - ),'zerobs_customer'); + $newLogID = zeroBS_addUpdateLog( + $cID, + -1, + -1, + array( + 'type' => __( 'Quote Created', 'zero-bs-crm' ), + 'shortdesc' => $noteShortDesc, + 'longdesc' => $note_long_description, + ), + 'zerobs_customer' + ); } - - } - - + } } +} // Adds an "accepted" log to contact (of quote) (if setting) - function zeroBSCRM_IA_AcceptedQuoteLog($obj=array()){ +function zeroBSCRM_IA_AcceptedQuoteLog( $obj = array() ) { + # if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_quote_accepted' ); - # if setting - $autoLogThis = zeroBSCRM_getSetting('autolog_quote_accepted'); + if ( $autoLogThis > 0 ) { - if ($autoLogThis > 0){ + global $zbs; - global $zbs; - - // retrieve quote - $quoteID = ''; if (is_array($obj) && isset($obj['id'])) $quoteID = $obj['id']; - $quote = $zbs->DAL->quotes->getQuote($quoteID); + // retrieve quote + $quoteID = ''; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $quoteID = $obj['id']; + } + $quote = $zbs->DAL->quotes->getQuote( $quoteID ); - if ( is_array($quote) && count($quote['contact']) > 0 ){ + if ( is_array( $quote ) && count( $quote['contact'] ) > 0 ) { - // get signed by if passed - $signedBy = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['signed']) && !empty($obj['data']['signed'])) $signedBy = $obj['data']['signed']; - // could get `ip` but not really user friendly/needed + // get signed by if passed + $signedBy = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['signed'] ) && ! empty( $obj['data']['signed'] ) ) { + $signedBy = $obj['data']['signed']; + } + // could get `ip` but not really user friendly/needed - // build str - $note_long_description = ''; - $noteShortDesc = ''; - if (!empty($quoteID)) $noteShortDesc .= '#'.$quoteID; - if (!empty($quoteTitle)) $noteShortDesc .= $quote['title']; - if (!empty($quoteValue)) $noteShortDesc .= ' ('.zeroBSCRM_formatCurrency($quote['value']).')'; - if (!empty($signedBy)) $note_long_description = __('Signed','zero-bs-crm').' '.$signedBy; + // build str + $note_long_description = ''; + $noteShortDesc = ''; + if ( ! empty( $quoteID ) ) { + $noteShortDesc .= '#' . $quoteID; + } + if ( ! empty( $quoteTitle ) ) { + $noteShortDesc .= $quote['title']; + } + if ( ! empty( $quoteValue ) ) { + $noteShortDesc .= ' (' . zeroBSCRM_formatCurrency( $quote['value'] ) . ')'; + } + if ( ! empty( $signedBy ) ) { + $note_long_description = __( 'Signed', 'zero-bs-crm' ) . ' ' . $signedBy; + } - if (is_array($quote['contact'])) foreach ($quote['contact'] as $contact){ + if ( is_array( $quote['contact'] ) ) { + foreach ( $quote['contact'] as $contact ) { - #} Add log - $newLogID = zeroBS_addUpdateLog($contact['id'],-1,-1,array( - 'type' => __('Quote: Accepted','zero-bs-crm'), + #} Add log + $newLogID = zeroBS_addUpdateLog( + $contact['id'], + -1, + -1, + array( + 'type' => __( 'Quote: Accepted', 'zero-bs-crm' ), 'shortdesc' => $noteShortDesc, - 'longdesc' => $note_long_description - ),'zerobs_customer'); - - } + 'longdesc' => $note_long_description, + ), + 'zerobs_customer' + ); } - + } } - - } - +} #} Adds a "created" log to customer (of quotes) (if setting) - function zeroBSCRM_IA_NewInvoiceLog($obj=array()){ +function zeroBSCRM_IA_NewInvoiceLog( $obj = array() ) { - # if setting - $autoLogThis = zeroBSCRM_getSetting('autolog_invoice_new'); + # if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_invoice_new' ); - if ($autoLogThis > 0){ - - #} Retrieve necessary info: - $noteAgainstIDs = array('contacts'=>array(),'companies'=>array()); - if (is_array($obj) && isset($obj['againstids']) && is_array($obj['againstids'])){ - - // trusting they're correctly passed... - if (isset($obj['againstids']['contacts']) && is_array($obj['againstids']['contacts'])) $noteAgainstIDs['contacts'] = $obj['againstids']['contacts']; - if (isset($obj['againstids']['companies']) && is_array($obj['againstids']['companies'])) $noteAgainstIDs['companies'] = $obj['againstids']['companies']; + if ( $autoLogThis > 0 ) { + #} Retrieve necessary info: + $noteAgainstIDs = array( + 'contacts' => array(), + 'companies' => array(), + ); + if ( is_array( $obj ) && isset( $obj['againstids'] ) && is_array( $obj['againstids'] ) ) { + + // trusting they're correctly passed... + if ( isset( $obj['againstids']['contacts'] ) && is_array( $obj['againstids']['contacts'] ) ) { + $noteAgainstIDs['contacts'] = $obj['againstids']['contacts']; } - $invoiceID = ''; if (is_array($obj) && isset($obj['id'])) $invoiceID = $obj['id']; - $invoiceRef = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['id_override']) && !empty($obj['data']['id_override'])) $invoiceRef = $obj['data']['id_override']; - $invoiceValue = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['total']) && !empty($obj['data']['total'])) $invoiceValue = zeroBSCRM_formatCurrency($obj['data']['total']); - $extsource = ''; if (is_array($obj) && is_array($obj['extsource']) && isset($obj['extsource']['source']) && !empty($obj['extsource']['source'])) $extsource = $obj['extsource']['source']; - $extsourceID = ''; if (is_array($obj) && is_array($obj['extsource']) && isset($obj['extsource']['uid']) && !empty($obj['extsource']['uid'])) $extsourceID = $obj['extsource']['uid']; - - // build str - $note_long_description = ''; - $noteShortDesc = ''; - if (!empty($invoiceID) && empty($invoiceRef)) $noteShortDesc .= '#'.$invoiceID; - if (!empty($invoiceRef)) $noteShortDesc .= $invoiceRef; - if (!empty($invoiceValue)) $noteShortDesc .= ' ('.$invoiceValue.')'; - if (!empty($extsource) && !empty($extsourceID)) $note_long_description = __('Created by','zero-bs-crm').' '.zeroBS_getExternalSourceTitle($extsource,$extsourceID); + if ( isset( $obj['againstids']['companies'] ) && is_array( $obj['againstids']['companies'] ) ) { + $noteAgainstIDs['companies'] = $obj['againstids']['companies']; + } + } + $invoiceID = ''; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $invoiceID = $obj['id']; + } + $invoiceRef = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['id_override'] ) && ! empty( $obj['data']['id_override'] ) ) { + $invoiceRef = $obj['data']['id_override']; + } + $invoiceValue = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['total'] ) && ! empty( $obj['data']['total'] ) ) { + $invoiceValue = zeroBSCRM_formatCurrency( $obj['data']['total'] ); + } + $extsource = ''; + if ( is_array( $obj ) && is_array( $obj['extsource'] ) && isset( $obj['extsource']['source'] ) && ! empty( $obj['extsource']['source'] ) ) { + $extsource = $obj['extsource']['source']; + } + $extsourceID = ''; + if ( is_array( $obj ) && is_array( $obj['extsource'] ) && isset( $obj['extsource']['uid'] ) && ! empty( $obj['extsource']['uid'] ) ) { + $extsourceID = $obj['extsource']['uid']; + } + + // build str + $note_long_description = ''; + $noteShortDesc = ''; + if ( ! empty( $invoiceID ) && empty( $invoiceRef ) ) { + $noteShortDesc .= '#' . $invoiceID; + } + if ( ! empty( $invoiceRef ) ) { + $noteShortDesc .= $invoiceRef; + } + if ( ! empty( $invoiceValue ) ) { + $noteShortDesc .= ' (' . $invoiceValue . ')'; + } + if ( ! empty( $extsource ) && ! empty( $extsourceID ) ) { + $note_long_description = __( 'Created by', 'zero-bs-crm' ) . ' ' . zeroBS_getExternalSourceTitle( $extsource, $extsourceID ); + } - if (is_array($noteAgainstIDs['contacts']) && count($noteAgainstIDs['contacts']) > 0) foreach ($noteAgainstIDs['contacts'] as $cID){ + if ( is_array( $noteAgainstIDs['contacts'] ) && count( $noteAgainstIDs['contacts'] ) > 0 ) { + foreach ( $noteAgainstIDs['contacts'] as $cID ) { #} Add log - $newLogID = zeroBS_addUpdateLog($cID,-1,-1,array( - 'type' => __('Invoice Created','zero-bs-crm'), - 'shortdesc' => $noteShortDesc, - 'longdesc' => $note_long_description - ),'zerobs_customer'); + $newLogID = zeroBS_addUpdateLog( + $cID, + -1, + -1, + array( + 'type' => __( 'Invoice Created', 'zero-bs-crm' ), + 'shortdesc' => $noteShortDesc, + 'longdesc' => $note_long_description, + ), + 'zerobs_customer' + ); } - - } - + } } +} #} Adds a "created" log to customer (of trans) (if setting) - function zeroBSCRM_IA_NewTransactionLog($obj=array()){ - - $newLogID = false; - - #} if setting - $autoLogThis = zeroBSCRM_getSetting('autolog_transaction_new'); +function zeroBSCRM_IA_NewTransactionLog( $obj = array() ) { - if ($autoLogThis > 0){ + $newLogID = false; - #} Retrieve necessary info: - $noteAgainstIDs = array('contacts'=>array(),'companies'=>array()); - if (is_array($obj) && isset($obj['againstids']) && is_array($obj['againstids'])){ + #} if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_transaction_new' ); - // trusting they're correctly passed... - if (isset($obj['againstids']['contacts']) && is_array($obj['againstids']['contacts'])) $noteAgainstIDs['contacts'] = $obj['againstids']['contacts']; - if (isset($obj['againstids']['companies']) && is_array($obj['againstids']['companies'])) $noteAgainstIDs['companies'] = $obj['againstids']['companies']; + if ( $autoLogThis > 0 ) { + #} Retrieve necessary info: + $noteAgainstIDs = array( + 'contacts' => array(), + 'companies' => array(), + ); + if ( is_array( $obj ) && isset( $obj['againstids'] ) && is_array( $obj['againstids'] ) ) { + + // trusting they're correctly passed... + if ( isset( $obj['againstids']['contacts'] ) && is_array( $obj['againstids']['contacts'] ) ) { + $noteAgainstIDs['contacts'] = $obj['againstids']['contacts']; } - $transactionID = ''; if (is_array($obj) && isset($obj['id'])) $transactionID = $obj['id']; - $transactionRef = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['ref']) && !empty($obj['data']['ref'])) $transactionRef = $obj['data']['ref']; - $transactionValue = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['total']) && !empty($obj['data']['total'])) $transactionValue = zeroBSCRM_formatCurrency($obj['data']['total']); - $extsource = ''; if (is_array($obj) && is_array($obj['extsource']) && isset($obj['extsource']['source']) && !empty($obj['extsource']['source'])) $extsource = $obj['extsource']['source']; - $extsourceID = ''; if (is_array($obj) && is_array($obj['extsource']) && isset($obj['extsource']['uid']) && !empty($obj['extsource']['uid'])) $extsourceID = $obj['extsource']['uid']; - - // build str - $note_long_description = ''; - $noteShortDesc = ''; - if (!empty($transactionID) && empty($transactionRef)) $noteShortDesc .= '#'.$transactionID; - if (!empty($transactionRef)) $noteShortDesc .= $transactionRef; - if (!empty($transactionValue)) $noteShortDesc .= ' ('.$transactionValue.')'; - if (!empty($extsource) && !empty($extsourceID)) $note_long_description = __('Created by','zero-bs-crm').' '.zeroBS_getExternalSourceTitle($extsource,$extsourceID); + if ( isset( $obj['againstids']['companies'] ) && is_array( $obj['againstids']['companies'] ) ) { + $noteAgainstIDs['companies'] = $obj['againstids']['companies']; + } + } + $transactionID = ''; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $transactionID = $obj['id']; + } + $transactionRef = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['ref'] ) && ! empty( $obj['data']['ref'] ) ) { + $transactionRef = $obj['data']['ref']; + } + $transactionValue = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['total'] ) && ! empty( $obj['data']['total'] ) ) { + $transactionValue = zeroBSCRM_formatCurrency( $obj['data']['total'] ); + } + $extsource = ''; + if ( is_array( $obj ) && is_array( $obj['extsource'] ) && isset( $obj['extsource']['source'] ) && ! empty( $obj['extsource']['source'] ) ) { + $extsource = $obj['extsource']['source']; + } + $extsourceID = ''; + if ( is_array( $obj ) && is_array( $obj['extsource'] ) && isset( $obj['extsource']['uid'] ) && ! empty( $obj['extsource']['uid'] ) ) { + $extsourceID = $obj['extsource']['uid']; + } + + // build str + $note_long_description = ''; + $noteShortDesc = ''; + if ( ! empty( $transactionID ) && empty( $transactionRef ) ) { + $noteShortDesc .= '#' . $transactionID; + } + if ( ! empty( $transactionRef ) ) { + $noteShortDesc .= $transactionRef; + } + if ( ! empty( $transactionValue ) ) { + $noteShortDesc .= ' (' . $transactionValue . ')'; + } + if ( ! empty( $extsource ) && ! empty( $extsourceID ) ) { + $note_long_description = __( 'Created by', 'zero-bs-crm' ) . ' ' . zeroBS_getExternalSourceTitle( $extsource, $extsourceID ); + } - if (is_array($noteAgainstIDs['contacts']) && count($noteAgainstIDs['contacts']) > 0) foreach ($noteAgainstIDs['contacts'] as $cID){ + if ( is_array( $noteAgainstIDs['contacts'] ) && count( $noteAgainstIDs['contacts'] ) > 0 ) { + foreach ( $noteAgainstIDs['contacts'] as $cID ) { #} Add log - $newLogID = zeroBS_addUpdateLog($cID,-1,-1,array( - 'type' => __('Transaction Created','zero-bs-crm'), - 'shortdesc' => $noteShortDesc, - 'longdesc' => $note_long_description - ),'zerobs_customer'); + $newLogID = zeroBS_addUpdateLog( + $cID, + -1, + -1, + array( + 'type' => __( 'Transaction Created', 'zero-bs-crm' ), + 'shortdesc' => $noteShortDesc, + 'longdesc' => $note_long_description, + ), + 'zerobs_customer' + ); } + } + } // / if autolog - } // / if autolog - - - return $newLogID; - - } + return $newLogID; +} #} Adds a "created" log to customer (of task) (if setting) - function zeroBSCRM_IA_NewEventLog($obj=array()){ - - $newLogID = false; +function zeroBSCRM_IA_NewEventLog( $obj = array() ) { - #} if setting - $autoLogThis = zeroBSCRM_getSetting('autolog_event_new'); + $newLogID = false; - #} if has id - $zbsNoteAgainstPostID = -1; if (is_array($obj) && isset($obj['againstid']) && $obj['againstid'] > 0) $zbsNoteAgainstPostID = (int)$obj['againstid']; + #} if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_event_new' ); - if ($autoLogThis > 0 && isset($zbsNoteAgainstPostID) && !empty($zbsNoteAgainstPostID)){ - - #} Retrieve necessary info: - $noteAgainstIDs = array('contacts'=>array(),'companies'=>array()); - if (is_array($obj) && isset($obj['againstids']) && is_array($obj['againstids'])){ + #} if has id + $zbsNoteAgainstPostID = -1; + if ( is_array( $obj ) && isset( $obj['againstid'] ) && $obj['againstid'] > 0 ) { + $zbsNoteAgainstPostID = (int) $obj['againstid']; + } - // trusting they're correctly passed... - if (isset($obj['againstids']['contacts']) && is_array($obj['againstids']['contacts'])) $noteAgainstIDs['contacts'] = $obj['againstids']['contacts']; - if (isset($obj['againstids']['companies']) && is_array($obj['againstids']['companies'])) $noteAgainstIDs['companies'] = $obj['againstids']['companies']; + if ( $autoLogThis > 0 && isset( $zbsNoteAgainstPostID ) && ! empty( $zbsNoteAgainstPostID ) ) { + #} Retrieve necessary info: + $noteAgainstIDs = array( + 'contacts' => array(), + 'companies' => array(), + ); + if ( is_array( $obj ) && isset( $obj['againstids'] ) && is_array( $obj['againstids'] ) ) { + + // trusting they're correctly passed... + if ( isset( $obj['againstids']['contacts'] ) && is_array( $obj['againstids']['contacts'] ) ) { + $noteAgainstIDs['contacts'] = $obj['againstids']['contacts']; + } + if ( isset( $obj['againstids']['companies'] ) && is_array( $obj['againstids']['companies'] ) ) { + $noteAgainstIDs['companies'] = $obj['againstids']['companies']; } - $taskID = ''; if (is_array($obj) && isset($obj['id'])) $taskID = $obj['id']; - $taskTitle = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['title']) && !empty($obj['data']['title'])) $taskTitle = $obj['data']['title']; - $taskDescription = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['desc']) && !empty($obj['data']['desc'])) $taskDescription = $obj['data']['desc']; - $taskStart = ''; if (is_array($obj) && is_array($obj['data']) && isset($obj['data']['start']) && !empty($obj['data']['start'])) $taskStart = zeroBSCRM_locale_utsToDatetime($obj['data']['start']); + } + $taskID = ''; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $taskID = $obj['id']; + } + $taskTitle = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['title'] ) && ! empty( $obj['data']['title'] ) ) { + $taskTitle = $obj['data']['title']; + } + $taskDescription = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['desc'] ) && ! empty( $obj['data']['desc'] ) ) { + $taskDescription = $obj['data']['desc']; + } + $taskStart = ''; + if ( is_array( $obj ) && is_array( $obj['data'] ) && isset( $obj['data']['start'] ) && ! empty( $obj['data']['start'] ) ) { + $taskStart = zeroBSCRM_locale_utsToDatetime( $obj['data']['start'] ); + } - // build str - $note_long_description = ''; - $noteShortDesc = ''; - if (!empty($taskID) && empty($taskTitle)) $noteShortDesc .= '#'.$taskID; - if (!empty($taskTitle)) $noteShortDesc .= $taskTitle; - if (!empty($taskDescription)) $note_long_description = $taskDescription; - if (!empty($taskStart)) { + // build str + $note_long_description = ''; + $noteShortDesc = ''; + if ( ! empty( $taskID ) && empty( $taskTitle ) ) { + $noteShortDesc .= '#' . $taskID; + } + if ( ! empty( $taskTitle ) ) { + $noteShortDesc .= $taskTitle; + } + if ( ! empty( $taskDescription ) ) { + $note_long_description = $taskDescription; + } + if ( ! empty( $taskStart ) ) { - // pad if filled - if (!empty($note_long_description)) $note_long_description .= '
'; + // pad if filled + if ( ! empty( $note_long_description ) ) { + $note_long_description .= '
'; + } - // add starting date - $note_long_description .= __('Starts at ','zero-bs-crm').' '.$taskStart; + // add starting date + $note_long_description .= __( 'Starts at ', 'zero-bs-crm' ) . ' ' . $taskStart; - } + } - if (is_array($noteAgainstIDs['contacts']) && count($noteAgainstIDs['contacts']) > 0) foreach ($noteAgainstIDs['contacts'] as $cID){ + if ( is_array( $noteAgainstIDs['contacts'] ) && count( $noteAgainstIDs['contacts'] ) > 0 ) { + foreach ( $noteAgainstIDs['contacts'] as $cID ) { #} Add log - $newLogID = zeroBS_addUpdateLog($cID,-1,-1,array( - 'type' => __('Task Created','zero-bs-crm'), - 'shortdesc' => $noteShortDesc, - 'longdesc' => $note_long_description - ),'zerobs_customer'); + $newLogID = zeroBS_addUpdateLog( + $cID, + -1, + -1, + array( + 'type' => __( 'Task Created', 'zero-bs-crm' ), + 'shortdesc' => $noteShortDesc, + 'longdesc' => $note_long_description, + ), + 'zerobs_customer' + ); } + } + } - } - - - return $newLogID; - - } + return $newLogID; +} /** * Catches new logs and updates contact 'last contacted' if contact type log @@ -642,143 +793,166 @@ function zeroBSCRM_IA_NewLogCatchContactsDB2( $obj = array() ) { } // is log against contact } - #} Adds a "created" log to customer (if setting) - function zeroBSCRM_IA_NewClientPortalUserLog($obj=array()){ - +function zeroBSCRM_IA_NewClientPortalUserLog( $obj = array() ) { - # if setting - $autoLogThis = zeroBSCRM_getSetting('autolog_clientportal_new'); + # if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_clientportal_new' ); - if ($autoLogThis > 0){ + if ( $autoLogThis > 0 ) { - #} Retrieve necessary info: - $zbsNoteAgainstPostID = -1; if (is_array($obj) && isset($obj['againstid']) && $obj['againstid'] > 0) $zbsNoteAgainstPostID = (int)$obj['againstid']; - #TRANSITIONTOMETANO - $userID = -1; if (is_array($obj) && isset($obj['id']) && $obj['id'] > 0) $userID = (int)$obj['id']; - $userEmail = ''; if (is_array($obj) && isset($obj['userEmail'])) $userEmail = $obj['userEmail']; - $noteShortDesc = ''; if (!empty($userEmail)) $noteShortDesc = __('Created with email',"zero-bs-crm").': '.$userEmail; + #} Retrieve necessary info: + $zbsNoteAgainstPostID = -1; + if ( is_array( $obj ) && isset( $obj['againstid'] ) && $obj['againstid'] > 0 ) { + $zbsNoteAgainstPostID = (int) $obj['againstid']; + } + #TRANSITIONTOMETANO + $userID = -1; + if ( is_array( $obj ) && isset( $obj['id'] ) && $obj['id'] > 0 ) { + $userID = (int) $obj['id']; + } + $userEmail = ''; + if ( is_array( $obj ) && isset( $obj['userEmail'] ) ) { + $userEmail = $obj['userEmail']; + } + $noteShortDesc = ''; + if ( ! empty( $userEmail ) ) { + $noteShortDesc = __( 'Created with email', 'zero-bs-crm' ) . ': ' . $userEmail; + } - if ($userID > 0) $noteShortDesc .= ' (#'.$userID.')'; + if ( $userID > 0 ) { + $noteShortDesc .= ' (#' . $userID . ')'; + } - if (isset($zbsNoteAgainstPostID) && !empty($zbsNoteAgainstPostID)){ + if ( isset( $zbsNoteAgainstPostID ) && ! empty( $zbsNoteAgainstPostID ) ) { - #} Add log - $newLogID = zeroBS_addUpdateContactLog($zbsNoteAgainstPostID,-1,-1,array( - 'type' => 'Client Portal User Created', + #} Add log + $newLogID = zeroBS_addUpdateContactLog( + $zbsNoteAgainstPostID, + -1, + -1, + array( + 'type' => 'Client Portal User Created', 'shortdesc' => $noteShortDesc, - 'longdesc' => '' - )); - - } + 'longdesc' => '', + ) + ); } - } - +} #} creates customer client portal user (if setting) - function zeroBSCRM_IA_NewCustomerClientPortal($obj=array()){ - - # if setting - $autoFireThis = zeroBSCRM_getSetting('portalusers'); - - if ($autoFireThis > 0){ - - #} Retrieve necessary info: - $userID = -1; if (is_array($obj) && isset($obj['id']) && $obj['id'] > 0) $userID = (int)$obj['id']; +function zeroBSCRM_IA_NewCustomerClientPortal( $obj = array() ) { - // yup - $okayToFire = true; + # if setting + $autoFireThis = zeroBSCRM_getSetting( 'portalusers' ); + if ( $autoFireThis > 0 ) { - // Specific status mode ================================== - - #} If using "specific statuses only" - $statusList = zeroBSCRM_getSetting('portalusers_status'); - if (!is_array($statusList) && (empty($statusList) || $statusList == 'all')){ - - // nothing to do - - } else { - - if (is_array($statusList)){ - - // generate a list of "Okay" statuses that this'll check later on... - $zbsStatusStr = zeroBSCRM_getCustomerStatuses(); - $zbsStatuses = explode(',', $zbsStatusStr); - $okayStatuses = array(); + #} Retrieve necessary info: + $userID = -1; + if ( is_array( $obj ) && isset( $obj['id'] ) && $obj['id'] > 0 ) { + $userID = (int) $obj['id']; + } - // cycle through settings + copy "full str" rather than "full_str" that it'll be saved as - foreach ($zbsStatuses as $statusStr){ + // yup + $okayToFire = true; - // permify - $statusKey = strtolower(str_replace(' ','_',str_replace(':','_',$statusStr))); + // Specific status mode ================================== - // present? - if (in_array($statusKey, $statusList)) $okayStatuses[] = $statusStr; + #} If using "specific statuses only" + $statusList = zeroBSCRM_getSetting( 'portalusers_status' ); + if ( ! is_array( $statusList ) && ( empty( $statusList ) || $statusList == 'all' ) ) { - } + // nothing to do - // is user's status in one of these? - $customerStatus = ''; if (isset($obj['customerMeta']) && is_array($obj['customerMeta']) && isset($obj['customerMeta']['status'])) $customerStatus = $obj['customerMeta']['status']; + } elseif ( is_array( $statusList ) ) { - // if no status, try fill from (whatever was added) to db - if (empty($customerStatus)){ + // generate a list of "Okay" statuses that this'll check later on... + $zbsStatusStr = zeroBSCRM_getCustomerStatuses(); + $zbsStatuses = explode( ',', $zbsStatusStr ); + $okayStatuses = array(); - $cMeta = zeroBS_getCustomerMeta($userID); + // cycle through settings + copy "full str" rather than "full_str" that it'll be saved as + foreach ( $zbsStatuses as $statusStr ) { - if (is_array($cMeta) && isset($cMeta['status'])) $customerStatus = $cMeta['status']; + // permify + $statusKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $statusStr ) ) ); - } + // present? + if ( in_array( $statusKey, $statusList ) ) { + $okayStatuses[] = $statusStr; + } + } - // check status - if (!empty($customerStatus) && in_array($customerStatus,$okayStatuses)) - $okayToFire = true; - else - $okayToFire = false; // customer status empty or not in approved list :) + // is user's status in one of these? + $customerStatus = ''; + if ( isset( $obj['customerMeta'] ) && is_array( $obj['customerMeta'] ) && isset( $obj['customerMeta']['status'] ) ) { + $customerStatus = $obj['customerMeta']['status']; + } - } else { + // if no status, try fill from (whatever was added) to db + if ( empty( $customerStatus ) ) { - // non-standard val for status list, override it to all - global $zbs; - $zbs->settings->update('portalusers_status','all'); + $cMeta = zeroBS_getCustomerMeta( $userID ); - // and let it fire.. + if ( is_array( $cMeta ) && isset( $cMeta['status'] ) ) { + $customerStatus = $cMeta['status']; } + } + // check status + if ( ! empty( $customerStatus ) && in_array( $customerStatus, $okayStatuses ) ) { + $okayToFire = true; + } else { + $okayToFire = false; // customer status empty or not in approved list :) } + } else { + + // non-standard val for status list, override it to all + global $zbs; + $zbs->settings->update( 'portalusers_status', 'all' ); - // / Specific status mode ================================== + // and let it fire.. - if ($okayToFire){ + } - // this'll check itself if already exists, so no harm in letting it (potentially) multifire - if ($userID > 0) zeroBSCRM_createClientPortalUserFromRecord($userID); + // / Specific status mode ================================== - } + if ( $okayToFire ) { + // this'll check itself if already exists, so no harm in letting it (potentially) multifire + if ( $userID > 0 ) { + zeroBSCRM_createClientPortalUserFromRecord( $userID ); + } } - } +} #} Compiles any segments which this contact fits in // works for new contacts + contact edits - function zeroBSCRM_IA_ContactSegmentCompiler($obj=array()){ +function zeroBSCRM_IA_ContactSegmentCompiler( $obj = array() ) { - # if setting - $autoCompileSegments = 1; + # if setting + $autoCompileSegments = 1; - if ($autoCompileSegments > 0){ + if ( $autoCompileSegments > 0 ) { - #} Retrieve necessary info: - $zbsNoteAgainstPostID = -1; if (is_array($obj) && isset($obj['id'])) $zbsNoteAgainstPostID = (int)$obj['id']; - $contactWasInSegments = array(); if (is_array($obj) && isset($obj['prevSegments']) && is_array($obj['prevSegments'])) $contactWasInSegments = $obj['prevSegments']; + #} Retrieve necessary info: + $zbsNoteAgainstPostID = -1; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $zbsNoteAgainstPostID = (int) $obj['id']; + } + $contactWasInSegments = array(); + if ( is_array( $obj ) && isset( $obj['prevSegments'] ) && is_array( $obj['prevSegments'] ) ) { + $contactWasInSegments = $obj['prevSegments']; + } - if (isset($zbsNoteAgainstPostID) && !empty($zbsNoteAgainstPostID)){ + if ( isset( $zbsNoteAgainstPostID ) && ! empty( $zbsNoteAgainstPostID ) ) { global $zbs; - $zbs->DAL->segments->compileSegmentsAffectedByContact($zbsNoteAgainstPostID,$contactWasInSegments); + $zbs->DAL->segments->compileSegmentsAffectedByContact( $zbsNoteAgainstPostID, $contactWasInSegments ); } } } @@ -791,7 +965,7 @@ function zeroBSCRM_IA_ContactSegmentCompiler($obj=array()){ * quote.update * */ - function zeroBSCRM_IA_quoteSegmentCompiler( $obj=array() ){ +function zeroBSCRM_IA_quoteSegmentCompiler( $obj = array() ) { global $zbs; @@ -809,7 +983,7 @@ function zeroBSCRM_IA_quoteSegmentCompiler( $obj=array() ){ * invoice.update * */ - function zeroBSCRM_IA_invoiceSegmentCompiler( $obj=array() ){ +function zeroBSCRM_IA_invoiceSegmentCompiler( $obj = array() ) { global $zbs; @@ -827,7 +1001,7 @@ function zeroBSCRM_IA_invoiceSegmentCompiler( $obj=array() ){ * transaction.update * */ - function zeroBSCRM_IA_transactionSegmentCompiler( $obj=array() ){ +function zeroBSCRM_IA_transactionSegmentCompiler( $obj = array() ) { global $zbs; @@ -838,223 +1012,239 @@ function zeroBSCRM_IA_transactionSegmentCompiler( $obj=array() ){ } #} when customer status changes, portal access can be revoked/added based on status (if setting) - function zeroBSCRM_IA_CustomerStatusChangePortalAndLog($obj=array()){ - - # if setting - $autoFireThis = zeroBSCRM_getSetting('portalusers'); - - if ($autoFireThis > 0){ - - #} Retrieve necessary info: - $userID = -1; if (is_array($obj) && isset($obj['id']) && $obj['id'] > 0) $userID = (int)$obj['id']; - - - #} If using "specific statuses only" - $statusList = zeroBSCRM_getSetting('portalusers_status'); - if (!is_array($statusList) && (empty($statusList) || $statusList == 'all')){ - - // nothing to do - all statuses allowed - - } else { - - if (is_array($statusList)){ - - // generate a list of "Okay" statuses that this'll check later on... - $zbsStatusStr = zeroBSCRM_getCustomerStatuses(); - $zbsStatuses = explode(',', $zbsStatusStr); - $okayStatuses = array(); - - // cycle through settings + copy "full str" rather than "full_str" that it'll be saved as - foreach ($zbsStatuses as $statusStr){ - - // permify - $statusKey = strtolower(str_replace(' ','_',str_replace(':','_',$statusStr))); +function zeroBSCRM_IA_CustomerStatusChangePortalAndLog( $obj = array() ) { - // present? - if (in_array($statusKey, $statusList)) $okayStatuses[] = $statusStr; + # if setting + $autoFireThis = zeroBSCRM_getSetting( 'portalusers' ); - } + if ( $autoFireThis > 0 ) { - // is user's status in one of these? - $customerStatus = ''; if (isset($obj['customerMeta']) && is_array($obj['customerMeta']) && isset($obj['customerMeta']['status'])) $customerStatus = $obj['customerMeta']['status']; - - // if no status, try fill from (whatever was added) to db - if (empty($customerStatus)){ - - $cMeta = zeroBS_getCustomerMeta($userID); + #} Retrieve necessary info: + $userID = -1; + if ( is_array( $obj ) && isset( $obj['id'] ) && $obj['id'] > 0 ) { + $userID = (int) $obj['id']; + } - if (is_array($cMeta) && isset($cMeta['status'])) $customerStatus = $cMeta['status']; + #} If using "specific statuses only" + $statusList = zeroBSCRM_getSetting( 'portalusers_status' ); + if ( ! is_array( $statusList ) && ( empty( $statusList ) || $statusList == 'all' ) ) { - } + // nothing to do - all statuses allowed - // check status - if (!empty($customerStatus) && in_array($customerStatus,$okayStatuses)){ - - // NEEDS account access + } elseif ( is_array( $statusList ) ) { - // already got? - $portalID = zeroBSCRM_getClientPortalUserID($userID); + // generate a list of "Okay" statuses that this'll check later on... + $zbsStatusStr = zeroBSCRM_getCustomerStatuses(); + $zbsStatuses = explode( ',', $zbsStatusStr ); + $okayStatuses = array(); - if (!empty($portalID) && $portalID > 0){ - - $isDisabled = zeroBSCRM_isCustomerPortalDisabled($userID); + // cycle through settings + copy "full str" rather than "full_str" that it'll be saved as + foreach ( $zbsStatuses as $statusStr ) { - // if disabled - if ($isDisabled){ + // permify + $statusKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $statusStr ) ) ); + // present? + if ( in_array( $statusKey, $statusList ) ) { + $okayStatuses[] = $statusStr; + } + } - // already got acc, make sure enabled - zeroBSCRM_customerPortalDisableEnable($userID,'enable'); + // is user's status in one of these? + $customerStatus = ''; + if ( isset( $obj['customerMeta'] ) && is_array( $obj['customerMeta'] ) && isset( $obj['customerMeta']['status'] ) ) { + $customerStatus = $obj['customerMeta']['status']; + } - $noteShortDesc = __('Access enabled (by change of status to',"zero-bs-crm").' "'.$customerStatus.'"'; + // if no status, try fill from (whatever was added) to db + if ( empty( $customerStatus ) ) { - #} Add log - $newLogID = zeroBS_addUpdateContactLog($userID,-1,-1,array( - 'type' => 'Client Portal Access Changed', - 'shortdesc' => $noteShortDesc, - 'longdesc' => '' - )); + $cMeta = zeroBS_getCustomerMeta( $userID ); - } + if ( is_array( $cMeta ) && isset( $cMeta['status'] ) ) { + $customerStatus = $cMeta['status']; + } + } - } else { + // check status + if ( ! empty( $customerStatus ) && in_array( $customerStatus, $okayStatuses ) ) { - // make acc - if ($userID > 0) { + // NEEDS account access - zeroBSCRM_createClientPortalUserFromRecord($userID); + // already got? + $portalID = zeroBSCRM_getClientPortalUserID( $userID ); - $noteShortDesc = __('Access created (by change of status to',"zero-bs-crm").' "'.$customerStatus.'"'; + if ( ! empty( $portalID ) && $portalID > 0 ) { - #} Add log - $newLogID = zeroBS_addUpdateContactLog($userID,-1,-1,array( - 'type' => 'Client Portal Access Changed', - 'shortdesc' => $noteShortDesc, - 'longdesc' => '' - )); + $isDisabled = zeroBSCRM_isCustomerPortalDisabled( $userID ); - } + // if disabled + if ( $isDisabled ) { - } + // already got acc, make sure enabled + zeroBSCRM_customerPortalDisableEnable( $userID, 'enable' ); - } else { + $noteShortDesc = __( 'Access enabled (by change of status to', 'zero-bs-crm' ) . ' "' . $customerStatus . '"'; - // SHOULD Not have account + #} Add log + $newLogID = zeroBS_addUpdateContactLog( + $userID, + -1, + -1, + array( + 'type' => 'Client Portal Access Changed', + 'shortdesc' => $noteShortDesc, + 'longdesc' => '', + ) + ); - // already got? - $portalID = zeroBSCRM_getClientPortalUserID($userID); + } + } else { - if (!empty($portalID) && $portalID > 0){ - - $isDisabled = zeroBSCRM_isCustomerPortalDisabled($userID); + // make acc + if ( $userID > 0 ) { - // if not already disabled - if (!$isDisabled){ + zeroBSCRM_createClientPortalUserFromRecord( $userID ); - // disable if found - zeroBSCRM_customerPortalDisableEnable($userID,'disable'); + $noteShortDesc = __( 'Access created (by change of status to', 'zero-bs-crm' ) . ' "' . $customerStatus . '"'; - $noteShortDesc = __('Access disabled (by change of status to',"zero-bs-crm").' "'.$customerStatus.'"'; + #} Add log + $newLogID = zeroBS_addUpdateContactLog( + $userID, + -1, + -1, + array( + 'type' => 'Client Portal Access Changed', + 'shortdesc' => $noteShortDesc, + 'longdesc' => '', + ) + ); - #} Add log - $newLogID = zeroBS_addUpdateContactLog($userID,-1,-1,array( - 'type' => 'Client Portal Access Changed', - 'shortdesc' => $noteShortDesc, - 'longdesc' => '' - )); + } + } + } else { - } + // SHOULD Not have account - } + // already got? + $portalID = zeroBSCRM_getClientPortalUserID( $userID ); + if ( ! empty( $portalID ) && $portalID > 0 ) { + $isDisabled = zeroBSCRM_isCustomerPortalDisabled( $userID ); - + // if not already disabled + if ( ! $isDisabled ) { - } + // disable if found + zeroBSCRM_customerPortalDisableEnable( $userID, 'disable' ); - } else { + $noteShortDesc = __( 'Access disabled (by change of status to', 'zero-bs-crm' ) . ' "' . $customerStatus . '"'; - // non-standard val for status list, override it to all - global $zbs; - $zbs->settings->update('portalusers_status','all'); + #} Add log + $newLogID = zeroBS_addUpdateContactLog( + $userID, + -1, + -1, + array( + 'type' => 'Client Portal Access Changed', + 'shortdesc' => $noteShortDesc, + 'longdesc' => '', + ) + ); - // and... nothing to do - all statuses allowed + } } - } + } else { + + // non-standard val for status list, override it to all + global $zbs; + $zbs->settings->update( 'portalusers_status', 'all' ); - // / Specific status mode ================================== + // and... nothing to do - all statuses allowed - } // / if autofire on :) + } - } + // / Specific status mode ================================== + } // / if autofire on :) +} #} Adds a "changed" log when customer status change (if setting) - function zeroBSCRM_IA_CustomerStatusChangeAutoLog($obj=array()){ - +function zeroBSCRM_IA_CustomerStatusChangeAutoLog( $obj = array() ) { - # if setting - $autoLogThis = zeroBSCRM_getSetting('autolog_customer_statuschange'); + # if setting + $autoLogThis = zeroBSCRM_getSetting( 'autolog_customer_statuschange' ); - if ($autoLogThis > 0){ + if ( $autoLogThis > 0 ) { - #} Retrieve necessary info: - $zbsNoteAgainstPostID = -1; if (is_array($obj) && isset($obj['againstid']) && $obj['againstid'] > 0) $zbsNoteAgainstPostID = (int)$obj['againstid']; - #TRANSITIONTOMETANO + #} Retrieve necessary info: + $zbsNoteAgainstPostID = -1; + if ( is_array( $obj ) && isset( $obj['againstid'] ) && $obj['againstid'] > 0 ) { + $zbsNoteAgainstPostID = (int) $obj['againstid']; + } + #TRANSITIONTOMETANO - // I nicely pass these... - $from = ''; if (is_array($obj) && isset($obj['from']) && !empty($obj['from'])) $from = $obj['from']; - $to = ''; if (is_array($obj) && isset($obj['to']) && !empty($obj['to'])) $to = $obj['to']; + // I nicely pass these... + $from = ''; + if ( is_array( $obj ) && isset( $obj['from'] ) && ! empty( $obj['from'] ) ) { + $from = $obj['from']; + } + $to = ''; + if ( is_array( $obj ) && isset( $obj['to'] ) && ! empty( $obj['to'] ) ) { + $to = $obj['to']; + } - if (isset($zbsNoteAgainstPostID) && !empty($zbsNoteAgainstPostID) && isset($to) && !empty($to)){ + if ( isset( $zbsNoteAgainstPostID ) && ! empty( $zbsNoteAgainstPostID ) && isset( $to ) && ! empty( $to ) ) { - $shortDesc = ''; - if (!empty($from)) - $shortDesc = __('From',"zero-bs-crm").' "'.$from.'" '.__('to',"zero-bs-crm").' "'.$to.'"'; - else - $shortDesc = __('To',"zero-bs-crm").' "'.$to.'"'; + $shortDesc = ''; + if ( ! empty( $from ) ) { + $shortDesc = __( 'From', 'zero-bs-crm' ) . ' "' . $from . '" ' . __( 'to', 'zero-bs-crm' ) . ' "' . $to . '"'; + } else { + $shortDesc = __( 'To', 'zero-bs-crm' ) . ' "' . $to . '"'; + } - #} Add log - $newLogID = zeroBS_addUpdateContactLog($zbsNoteAgainstPostID,-1,-1,array( - 'type' => 'Status Change', + #} Add log + $newLogID = zeroBS_addUpdateContactLog( + $zbsNoteAgainstPostID, + -1, + -1, + array( + 'type' => 'Status Change', 'shortdesc' => $shortDesc, - 'longdesc' => '' - )); - - } + 'longdesc' => '', + ) + ); } - } +} +/* +====================================================== + / Internal Automator Recipe Functions + ====================================================== */ -/* ====================================================== - / Internal Automator Recipe Functions - ====================================================== */ - - - -/* ====================================================== - Internal Automator Recipe Functions - WP HOOK tieins... just middlemen here really - ====================================================== */ +/* +====================================================== + Internal Automator Recipe Functions - WP HOOK tieins... just middlemen here really + ====================================================== */ #} Fires the hook & passes in the obj, for those who still want to use wp_hook's rather than IA Automator - #} Fires on 'customer.new' IA - function zeroBSCRM_IA_NewCustomerWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) { + #} Fires on 'customer.new' IA +function zeroBSCRM_IA_NewCustomerWPHook( $obj = array() ) { - do_action( 'jpcrm_after_contact_insert', $obj['id'] ); + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { - // legacy, use `jpcrm_after_contact_insert` from 5.3+ - do_action( 'zbs_new_customer', $obj['id'] ); + do_action( 'jpcrm_after_contact_insert', $obj['id'] ); - } + // legacy, use `jpcrm_after_contact_insert` from 5.3+ + do_action( 'zbs_new_customer', $obj['id'] ); } +} /** * Fires on 'contact.update', 'contact.email.update', and 'contact.status.update IA. @@ -1074,22 +1264,24 @@ function zeroBSCRM_IA_EditCustomerWPHook( $obj = array() ) { } #} Fires on 'customer.vitals.edit' IA. - function zeroBSCRM_IA_EditCustomerVitalsWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_edit_customer_vitals', $obj['id']); +function zeroBSCRM_IA_EditCustomerVitalsWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_edit_customer_vitals', $obj['id'] ); } +} /** * Fires on 'contact.email.update' IA. Now legacy, redirecting to zeroBSCRM_IA_EditCustomerWPHook * * @param array $obj An array holding contact object data. */ - function zeroBSCRM_IA_EditCustomerEmailWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_edit_customer_email', $obj['id']); +function zeroBSCRM_IA_EditCustomerEmailWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_edit_customer_email', $obj['id'] ); } +} /** * Fires on 'contact.delete' IA. @@ -1109,7 +1301,7 @@ function zeroBSCRM_IA_DeleteCustomerWPHook( $obj = array() ) { * * @param array $obj An array holding contact object data. */ - function zeroBSCRM_IA_BeforeDeleteCustomerWPHook($obj=array()){ +function zeroBSCRM_IA_BeforeDeleteCustomerWPHook( $obj = array() ) { if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { do_action( 'jpcrm_before_delete_contact', $obj ); } @@ -1143,24 +1335,27 @@ function zeroBSCRM_IA_DeleteCompanyWPHook( $obj = array() ) { do_action( 'zbs_delete_company', $obj['id'] ); } } - #} Fires on 'quote.new' IA - function zeroBSCRM_IA_NewQuoteWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_new_quote', $obj['id']); + #} Fires on 'quote.new' IA +function zeroBSCRM_IA_NewQuoteWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_new_quote', $obj['id'] ); } - #} Fires on 'quote.accepted' IA - function zeroBSCRM_IA_AcceptedQuoteWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('jpcrm_quote_accepted', $obj['id']); +} + #} Fires on 'quote.accepted' IA +function zeroBSCRM_IA_AcceptedQuoteWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'jpcrm_quote_accepted', $obj['id'] ); } - #} Fires on 'quote.delete' IA - function zeroBSCRM_IA_DeleteQuoteWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_delete_quote', $obj['id']); +} + #} Fires on 'quote.delete' IA +function zeroBSCRM_IA_DeleteQuoteWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_delete_quote', $obj['id'] ); } +} /** * Fires on 'invoice.new' IA. @@ -1197,57 +1392,64 @@ function zeroBSCRM_IA_DeleteInvoiceWPHook( $obj = array() ) { } } - #} Fires on 'transaction.new' IA - function zeroBSCRM_IA_NewTransactionWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_new_transaction', $obj['id']); + #} Fires on 'transaction.new' IA +function zeroBSCRM_IA_NewTransactionWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_new_transaction', $obj['id'] ); } - #} Fires on 'transaction.delete' IA - function zeroBSCRM_IA_DeleteTransactionWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_delete_transaction', $obj['id']); +} + #} Fires on 'transaction.delete' IA +function zeroBSCRM_IA_DeleteTransactionWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_delete_transaction', $obj['id'] ); } - #} Fires on 'event.new' IA - function zeroBSCRM_IA_NewEventWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_new_event', $obj['id']); +} + #} Fires on 'event.new' IA +function zeroBSCRM_IA_NewEventWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_new_event', $obj['id'] ); } - #} Fires on 'event.update' IA - function zeroBSCRM_IA_UpdateEventWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_update_event', $obj['id']); +} + #} Fires on 'event.update' IA +function zeroBSCRM_IA_UpdateEventWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_update_event', $obj['id'] ); } - #} Fires on 'event.delete' IA - function zeroBSCRM_IA_DeleteEventWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_delete_event', $obj['id']); +} + #} Fires on 'event.delete' IA +function zeroBSCRM_IA_DeleteEventWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_delete_event', $obj['id'] ); } - #} Fires on 'clientwpuser.new' IA - function zeroBSCRM_IA_NewClientPortalUserHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_new_client_portal_user', $obj['id']); +} + #} Fires on 'clientwpuser.new' IA +function zeroBSCRM_IA_NewClientPortalUserHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_new_client_portal_user', $obj['id'] ); } - #} Fires on 'form.delete' IA - function zeroBSCRM_IA_DeleteFormWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_delete_form', $obj['id']); +} + #} Fires on 'form.delete' IA +function zeroBSCRM_IA_DeleteFormWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_delete_form', $obj['id'] ); } - #} Fires on 'segment.delete' IA - function zeroBSCRM_IA_DeleteSegmentWPHook($obj=array()){ - - if (is_array($obj) && isset($obj['id']) && !empty($obj['id'])) do_action('zbs_delete_segment', $obj['id']); +} + #} Fires on 'segment.delete' IA +function zeroBSCRM_IA_DeleteSegmentWPHook( $obj = array() ) { + if ( is_array( $obj ) && isset( $obj['id'] ) && ! empty( $obj['id'] ) ) { + do_action( 'zbs_delete_segment', $obj['id'] ); } +} - - -/* ====================================================== - / Internal Automator Recipe Functions - WP HOOK tieins - ====================================================== */ +/* +====================================================== + / Internal Automator Recipe Functions - WP HOOK tieins + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Inventory.php b/projects/plugins/crm/includes/ZeroBSCRM.Inventory.php index 7921895a1af2..0c236bc9c443 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Inventory.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Inventory.php @@ -1,5 +1,6 @@ - 0) $due = (int)$zbsInvoice['due_date']; + global $zbs; - // compare (could give days difference here, but not req yet.) - if ($due > time()){ - // not due - return false; - } else { - // due - return true; - } + if ( is_array( $zbsInvoice ) ) { - } + // first get due + $due = 0; + if ( isset( $zbsInvoice['due_date'] ) && $zbsInvoice['due_date'] > 0 ) { + $due = (int) $zbsInvoice['due_date']; + } - return false; + // compare (could give days difference here, but not req yet.) + if ( $due > time() ) { + // not due + return false; + } else { + // due + return true; + } + } + return false; } - -/* ====================================================== - ZBS Invoicing - REMOVE previous submit meta box + replace with custom - ====================================================== */ +/* +====================================================== + ZBS Invoicing - REMOVE previous submit meta box + replace with custom + ====================================================== */ #} This adds our own save box -function zeroBSCRM_replace_invoice_submit_meta_box() -{ - - #} remove typical submit box: - remove_meta_box('submitdiv', 'zerobs_invoice', 'core'); // $item represents post_type - - #} Include/initialise custom submitbox - require_once( ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes.SubmitBoxes.php'); - +function zeroBSCRM_replace_invoice_submit_meta_box() { + + #} remove typical submit box: + remove_meta_box( 'submitdiv', 'zerobs_invoice', 'core' ); // $item represents post_type + + #} Include/initialise custom submitbox + require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes.SubmitBoxes.php'; } add_action( 'admin_init', 'zeroBSCRM_replace_invoice_submit_meta_box' ); #} This specifies 1 column pre-save, 2 columns post-save :) -function zeroBSCRM_invoiceBuilderColumnCount(){ +function zeroBSCRM_invoiceBuilderColumnCount() { - global $post; - if (isset($post->post_status) && $post->post_status != "auto-draft") return 2; - - return 2; + global $post; + if ( isset( $post->post_status ) && $post->post_status != 'auto-draft' ) { + return 2; + } + return 2; } -add_filter('get_user_option_screen_layout_zerobs_invoice', 'zeroBSCRM_invoiceBuilderColumnCount' ); +add_filter( 'get_user_option_screen_layout_zerobs_invoice', 'zeroBSCRM_invoiceBuilderColumnCount' ); - -/* ====================================================== - ZBS Invoicing - HTML GENERATOR - ====================================================== */ +/* +====================================================== + ZBS Invoicing - HTML GENERATOR + ====================================================== */ #} Generates the HTML of an invoice based on the template in templates/invoices/invoice-pdf.html #} if $return, it'll return, otherwise it'll echo + exit #} --------- Notes: -#} ... there's several ways we COULD do this, -#} ... suggest we explore this way first, then re-discuss, +#} ... there's several ways we COULD do this, +#} ... suggest we explore this way first, then re-discuss, #} ... Benefits of this inc. easy to theme ;) just create variations of invoice.html // Note: This is primarily used to generate PDF invoice html. (dig down and see use if "zeroBSCRM_invoicing_generateInvoiceHTML($invoiceID,'pdf'") -function zeroBSCRM_invoice_generateInvoiceHTML($invoicePostID=-1,$return=true){ +function zeroBSCRM_invoice_generateInvoiceHTML( $invoicePostID = -1, $return = true ) { - if (!empty($invoicePostID)){ + if ( ! empty( $invoicePostID ) ) { - global $zbs; - return zeroBSCRM_invoice_generateInvoiceHTML_v3( $invoicePostID, $return ); + global $zbs; + return zeroBSCRM_invoice_generateInvoiceHTML_v3( $invoicePostID, $return ); - } + } - #} Empty inv id - return false; + #} Empty inv id + return false; } // invoice html generation 3.0+ -function zeroBSCRM_invoice_generateInvoiceHTML_v3( $invoiceID=-1, $return=true ){ +function zeroBSCRM_invoice_generateInvoiceHTML_v3( $invoiceID = -1, $return = true ) { - global $zbs; + global $zbs; - if (!empty($invoiceID)){ + if ( ! empty( $invoiceID ) ) { - // Discern template and retrieve - $global_invoice_pdf_template = zeroBSCRM_getSetting('inv_pdf_template'); - if ( !empty( $global_invoice_pdf_template ) ){ - $templatedHTML = jpcrm_retrieve_template( $global_invoice_pdf_template, false ); - } + // Discern template and retrieve + $global_invoice_pdf_template = zeroBSCRM_getSetting( 'inv_pdf_template' ); + if ( ! empty( $global_invoice_pdf_template ) ) { + $templatedHTML = jpcrm_retrieve_template( $global_invoice_pdf_template, false ); + } - // fallback to default template - if ( !isset( $templatedHTML ) || empty( $templatedHTML ) ){ + // fallback to default template + if ( ! isset( $templatedHTML ) || empty( $templatedHTML ) ) { - // template failed as setting potentially holds out of date (removed) template - // so use the default - $templatedHTML = jpcrm_retrieve_template( 'invoices/invoice-pdf.html', false ); + // template failed as setting potentially holds out of date (removed) template + // so use the default + $templatedHTML = jpcrm_retrieve_template( 'invoices/invoice-pdf.html', false ); - } + } - #} Act - if (!empty($templatedHTML)){ + #} Act + if ( ! empty( $templatedHTML ) ) { - // Over-ride the #MSGCONTENT# part - $placeholder_templating = $zbs->get_templating(); + // Over-ride the #MSGCONTENT# part + $placeholder_templating = $zbs->get_templating(); - // replace the content with our new ID ... (gets our content template info and replaces ###MSG CONTENT) - $message_content = zeroBSCRM_mailTemplate_get(ZBSEMAIL_EMAILINVOICE); - $message_content = $message_content->zbsmail_body; - $templatedHTML = $placeholder_templating->replace_single_placeholder( 'msg-content', $message_content, $templatedHTML ); + // replace the content with our new ID ... (gets our content template info and replaces ###MSG CONTENT) + $message_content = zeroBSCRM_mailTemplate_get( ZBSEMAIL_EMAILINVOICE ); + $message_content = $message_content->zbsmail_body; + $templatedHTML = $placeholder_templating->replace_single_placeholder( 'msg-content', $message_content, $templatedHTML ); - // for v3.0 WH split out the data-retrieval from scattering amongst this func, unified here: - // translated the below cpt way into dal / v3.0: + // for v3.0 WH split out the data-retrieval from scattering amongst this func, unified here: + // translated the below cpt way into dal / v3.0: - // this was refactored as was duplicate code. - // now all wired through zeroBSCRM_invoicing_generateInvoiceHTML - $html = zeroBSCRM_invoicing_generateInvoiceHTML($invoiceID,'pdf',$templatedHTML); + // this was refactored as was duplicate code. + // now all wired through zeroBSCRM_invoicing_generateInvoiceHTML + $html = zeroBSCRM_invoicing_generateInvoiceHTML( $invoiceID, 'pdf', $templatedHTML ); // return if ( ! $return ) { @@ -150,54 +151,53 @@ function zeroBSCRM_invoice_generateInvoiceHTML_v3( $invoiceID=-1, $return=true ) // this was clunky, so split into 3.0 and <3.0 versions. // ultimately this is much like zeroBSCRM_invoice_generateInvoiceHTML // ... should refactor the bits that are the same -function zeroBSCRM_invoice_generatePortalInvoiceHTML($invoicePostID=-1,$return=true){ - global $zbs; +function zeroBSCRM_invoice_generatePortalInvoiceHTML( $invoicePostID = -1, $return = true ) { + global $zbs; - if (!empty($invoicePostID)){ - return zeroBSCRM_invoice_generatePortalInvoiceHTML_v3( $invoicePostID, $return ); - } + if ( ! empty( $invoicePostID ) ) { + return zeroBSCRM_invoice_generatePortalInvoiceHTML_v3( $invoicePostID, $return ); + } - #} Empty inv id - return false; + #} Empty inv id + return false; } - // 3.0+ -function zeroBSCRM_invoice_generatePortalInvoiceHTML_v3($invoiceID=-1,$return=true){ +function zeroBSCRM_invoice_generatePortalInvoiceHTML_v3( $invoiceID = -1, $return = true ) { - global $zbs; + global $zbs; - if (!empty($invoiceID)){ + if ( ! empty( $invoiceID ) ) { - // Discern template and retrieve - $global_invoice_portal_template = zeroBSCRM_getSetting('inv_portal_template'); - if ( !empty( $global_invoice_portal_template ) ){ - $html = jpcrm_retrieve_template( $global_invoice_portal_template, false ); - } + // Discern template and retrieve + $global_invoice_portal_template = zeroBSCRM_getSetting( 'inv_portal_template' ); + if ( ! empty( $global_invoice_portal_template ) ) { + $html = jpcrm_retrieve_template( $global_invoice_portal_template, false ); + } - // fallback to default template - if ( !isset( $html ) || empty( $html ) ){ + // fallback to default template + if ( ! isset( $html ) || empty( $html ) ) { - // template failed as setting potentially holds out of date (removed) template - // so use the default - $html = jpcrm_retrieve_template( 'invoices/portal-invoice.html', false ); + // template failed as setting potentially holds out of date (removed) template + // so use the default + $html = jpcrm_retrieve_template( 'invoices/portal-invoice.html', false ); - } + } - #} Act - if (!empty($html)){ + #} Act + if ( ! empty( $html ) ) { - // load templating - $placeholder_templating = $zbs->get_templating(); + // load templating + $placeholder_templating = $zbs->get_templating(); - // replace the content with our new ID ... (gets our content template info and replaces ###MSG CONTENT) - $message_content = zeroBSCRM_mailTemplate_get(ZBSEMAIL_EMAILINVOICE); - $message_content = $message_content->zbsmail_body; - $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $message_content, $html ); + // replace the content with our new ID ... (gets our content template info and replaces ###MSG CONTENT) + $message_content = zeroBSCRM_mailTemplate_get( ZBSEMAIL_EMAILINVOICE ); + $message_content = $message_content->zbsmail_body; + $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $message_content, $html ); - // this was refactored as was duplicate code. - // now all wired through zeroBSCRM_invoicing_generateInvoiceHTML - $html = zeroBSCRM_invoicing_generateInvoiceHTML($invoiceID,'portal',$html); + // this was refactored as was duplicate code. + // now all wired through zeroBSCRM_invoicing_generateInvoiceHTML + $html = zeroBSCRM_invoicing_generateInvoiceHTML( $invoiceID, 'portal', $html ); // return if ( ! $return ) { @@ -213,7 +213,7 @@ function zeroBSCRM_invoice_generatePortalInvoiceHTML_v3($invoiceID=-1,$return=tr return false; } -function zbs_invoice_generate_pdf(){ +function zbs_invoice_generate_pdf() { // download flag if ( isset( $_POST['zbs_invoicing_download_pdf'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing @@ -296,15 +296,15 @@ function jpcrm_invoice_generate_pdf( $invoice_id = -1 ) { // LEGACY, should now be using zeroBSCRM_invoice_generateInvoiceHTML // still used in Client Portal Pro -function zbs_invoice_html($invoicePostID){ +function zbs_invoice_html( $invoicePostID ) { - $html = zeroBSCRM_invoice_generateInvoiceHTML($invoicePostID); + $html = zeroBSCRM_invoice_generateInvoiceHTML( $invoicePostID ); - return $html; + return $html; } #} this generates a PDF statement for a contact, either returning the filepath or a PDF download prompt -function zeroBSCRM_invoicing_generateStatementPDF( $contactID = -1, $returnPDF = false ){ +function zeroBSCRM_invoicing_generateStatementPDF( $contactID = -1, $returnPDF = false ) { if ( ! zeroBSCRM_permsInvoices() ) { exit( 0 ); @@ -312,74 +312,75 @@ function zeroBSCRM_invoicing_generateStatementPDF( $contactID = -1, $returnPDF = global $zbs; - #} Check ID - $contactID = (int)$contactID; - #} If user has no perms, or id not present, die - if (!zeroBSCRM_permsInvoices() || empty($contactID) || $contactID <= 0){ + #} Check ID + $contactID = (int) $contactID; + #} If user has no perms, or id not present, die + if ( ! zeroBSCRM_permsInvoices() || empty( $contactID ) || $contactID <= 0 ) { die( 0 ); - } - - $html = zeroBSCRM_invoicing_generateStatementHTML($contactID); + } - // build PDF - $dompdf = $zbs->pdf_engine(); - $dompdf->loadHtml($html,'UTF-8'); - $dompdf->render(); + $html = zeroBSCRM_invoicing_generateStatementHTML( $contactID ); - // target dir - $upload_dir = wp_upload_dir(); - $zbsInvoicingDir = $upload_dir['basedir'].'/invoices/'; + // build PDF + $dompdf = $zbs->pdf_engine(); + $dompdf->loadHtml( $html, 'UTF-8' ); + $dompdf->render(); - if ( ! file_exists( $zbsInvoicingDir ) ) { - wp_mkdir_p( $zbsInvoicingDir ); - } - // got it? - if ( ! file_exists( $zbsInvoicingDir ) ) { - return false; - } + // target dir + $upload_dir = wp_upload_dir(); + $zbsInvoicingDir = $upload_dir['basedir'] . '/invoices/'; - // make a hash - // here we've tried to protect against someone overriding the security, - // but if they're inside... it's too late anyhow. - $hash = wp_generate_password(14, false); - if (empty($hash) || strlen($hash) < 14) $hash = md5(time().'xcsac'); // backup - - $statementFilename = $zbsInvoicingDir.$hash.'-'.__('statement','zero-bs-crm').'-'.$contactID.'.pdf'; + if ( ! file_exists( $zbsInvoicingDir ) ) { + wp_mkdir_p( $zbsInvoicingDir ); + } + // got it? + if ( ! file_exists( $zbsInvoicingDir ) ) { + return false; + } - //save the pdf file on the server - file_put_contents($statementFilename, $dompdf->output()); + // make a hash + // here we've tried to protect against someone overriding the security, + // but if they're inside... it's too late anyhow. + $hash = wp_generate_password( 14, false ); + if ( empty( $hash ) || strlen( $hash ) < 14 ) { + $hash = md5( time() . 'xcsac' ); // backup + } - if (file_exists( $statementFilename )) { + $statementFilename = $zbsInvoicingDir . $hash . '-' . __( 'statement', 'zero-bs-crm' ) . '-' . $contactID . '.pdf'; - // if return pdf, return, otherwise return filepath - if ($returnPDF){ + // save the pdf file on the server + file_put_contents( $statementFilename, $dompdf->output() ); - //print the pdf file to the screen for saving - header('Content-type: application/pdf'); - header( 'Content-Disposition: attachment; filename="' . __( 'statement', 'zero-bs-crm' ) . '-' . $contactID . '.pdf' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - header('Content-Transfer-Encoding: binary'); - header('Content-Length: ' . filesize($statementFilename)); - header('Accept-Ranges: bytes'); - readfile($statementFilename); + if ( file_exists( $statementFilename ) ) { - //delete the PDF file once it's been read (i.e. downloaded) - unlink($statementFilename); + // if return pdf, return, otherwise return filepath + if ( $returnPDF ) { - } else { + // print the pdf file to the screen for saving + header( 'Content-type: application/pdf' ); + header( 'Content-Disposition: attachment; filename="' . __( 'statement', 'zero-bs-crm' ) . '-' . $contactID . '.pdf' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + header( 'Content-Transfer-Encoding: binary' ); + header( 'Content-Length: ' . filesize( $statementFilename ) ); + header( 'Accept-Ranges: bytes' ); + readfile( $statementFilename ); - return $statementFilename; + // delete the PDF file once it's been read (i.e. downloaded) + unlink( $statementFilename ); - } + } else { + return $statementFilename; - } // if file + } + } // if file - return false; + return false; } -/* ====================================================== - ZBS Invoicing - STATEMENT HTML GENERATOR - ====================================================== */ +/* +====================================================== + ZBS Invoicing - STATEMENT HTML GENERATOR + ====================================================== */ // phpcs:ignore Squiz.Commenting.FunctionComment.MissingParamTag /** @@ -583,7 +584,7 @@ function zeroBSCRM_invoicing_generateStatementHTML_v3( $contact_id = -1, $return // due if ( $invoice['due_date'] <= 0 ) { - //no due date; + // no due date; $due_date_str = __( 'No due date', 'zero-bs-crm' ); } else { @@ -788,7 +789,7 @@ function zeroBSCRM_invoicing_generateInvoiceHTML( $invoice_id = -1, $template = // due if ( $invoice['due_date'] <= 0 ) { - //no due date + // no due date $due_date_str = __( 'No due date', 'zero-bs-crm' ); } else { @@ -954,7 +955,7 @@ function zeroBSCRM_invoicing_generateInvoiceHTML( $invoice_id = -1, $template = // == Build biz info table. - //the business info from the settings + // the business info from the settings $zbs_biz_name = zeroBSCRM_getSetting( 'businessname' ); $zbs_biz_yourname = zeroBSCRM_getSetting( 'businessyourname' ); $zbs_biz_extra = zeroBSCRM_getSetting( 'businessextra' ); @@ -1258,7 +1259,7 @@ function zeroBSCRM_invoicing_generateInvoiceHTML( $invoice_id = -1, $template = } // Used to generate specific part of invoice pdf: Biz table (Pay To) -function zeroBSCRM_invoicing_generateInvPart_bizTable($args=array()){ +function zeroBSCRM_invoicing_generateInvPart_bizTable( $args = array() ) { #} =========== LOAD ARGS ============== $defaultArgs = array( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -1271,7 +1272,21 @@ function zeroBSCRM_invoicing_generateInvPart_bizTable($args=array()){ 'template' => 'pdf', // this'll choose between the html output variants below, e.g. pdf, portal, notification - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) { if (is_array($args[$argK])){ $newData = $$argK; if (!is_array($newData)) $newData = array(); foreach ($args[$argK] as $subK => $subV){ $newData[$subK] = $subV; }$$argK = $newData;} else { $$argK = $args[$argK]; } } } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + if ( is_array( $args[ $argK ] ) ) { + $newData = $$argK; + if ( ! is_array( $newData ) ) { + $newData = array(); + } foreach ( $args[ $argK ] as $subK => $subV ) { + $newData[ $subK ] = $subV; + }$$argK = $newData; + } else { + $$argK = $args[ $argK ]; } + } + } #} =========== / LOAD ARGS ============= $biz_info_table = ''; @@ -1381,78 +1396,72 @@ function zeroBSCRM_invoicing_generateInvPart_custTable( $inv_to = array(), $temp $invoice_customer_info_table_html .= '
'; - //filter the whole thing if you really want to modify it + // filter the whole thing if you really want to modify it $invoice_customer_info_table_html = apply_filters( 'zbs_invoice_customer_info_table', $invoice_customer_info_table_html ); return $invoice_customer_info_table_html; } - - - - /* * Generates html string to output customer (contact or company) custom field lines for templating * * @param array $customer - a contact|company object * @param string $template - 'pdf', 'notification', or 'portal' -* +* * @return string HTML */ -function jpcrm_invoicing_generate_customer_custom_fields_lines( $customer, $template ){ +function jpcrm_invoicing_generate_customer_custom_fields_lines( $customer, $template ) { - global $zbs; + global $zbs; - $customer_custom_fields_html = ''; + $customer_custom_fields_html = ''; - // retrieve custom fields to pass through - // contact or company? - if ( $customer['objtype'] == ZBS_TYPE_CONTACT ){ + // retrieve custom fields to pass through + // contact or company? + if ( $customer['objtype'] == ZBS_TYPE_CONTACT ) { - $custom_fields_to_include = zeroBSCRM_getSetting( 'contactcustomfields' ); + $custom_fields_to_include = zeroBSCRM_getSetting( 'contactcustomfields' ); - } elseif ( $customer['objtype'] == ZBS_TYPE_COMPANY ){ + } elseif ( $customer['objtype'] == ZBS_TYPE_COMPANY ) { - $custom_fields_to_include = zeroBSCRM_getSetting( 'companycustomfields' ); + $custom_fields_to_include = zeroBSCRM_getSetting( 'companycustomfields' ); - } else { + } else { - // no type? ¯\_(ツ)_/¯ - return ''; + // no type? ¯\_(ツ)_/¯ + return ''; - } - - - if ( !empty( $custom_fields_to_include ) ){ + } - // split the csv - $custom_fields_to_include = array_map( 'trim', explode( ',', $custom_fields_to_include ) ); + if ( ! empty( $custom_fields_to_include ) ) { - // retrieve fields - $invoice_custom_fields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => $customer['objtype'] ) ); + // split the csv + $custom_fields_to_include = array_map( 'trim', explode( ',', $custom_fields_to_include ) ); - // build custom fields string. - // here we immitate what we expect the HTML to be, which will be errorsome if people modify heavily. - // for now it's better than no custom fields, let's see if people have issue with this approach. - foreach ( $invoice_custom_fields as $field_key => $field_info){ + // retrieve fields + $invoice_custom_fields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => $customer['objtype'] ) ); - // where user has set the field in settings - if ( in_array( $field_key, $custom_fields_to_include ) ){ + // build custom fields string. + // here we immitate what we expect the HTML to be, which will be errorsome if people modify heavily. + // for now it's better than no custom fields, let's see if people have issue with this approach. + foreach ( $invoice_custom_fields as $field_key => $field_info ) { - $custom_field_str = ''; + // where user has set the field in settings + if ( in_array( $field_key, $custom_fields_to_include ) ) { - if ( isset( $customer[ $field_key ] ) && $customer[ $field_key ] ){ + $custom_field_str = ''; - $custom_field_str = $customer[ $field_key ]; + if ( isset( $customer[ $field_key ] ) && $customer[ $field_key ] ) { - // catch formatted dates - if ( isset( $customer[ $field_key . '_cfdate' ] ) ){ + $custom_field_str = $customer[ $field_key ]; - $custom_field_str = $customer[ $field_key . '_cfdate' ]; + // catch formatted dates + if ( isset( $customer[ $field_key . '_cfdate' ] ) ) { - } + $custom_field_str = $customer[ $field_key . '_cfdate' ]; - } + } + } // skip empties if ( empty( $custom_field_str ) ) { @@ -1478,52 +1487,51 @@ function jpcrm_invoicing_generate_customer_custom_fields_lines( $customer, $temp return $customer_custom_fields_html; } - /* * Generates html string to output invoice custom field lines for templating * * @param array $invoice - an invoice object * @param string $template - 'pdf', 'notification', or 'portal' -* +* * @return string HTML */ -function jpcrm_invoicing_generate_invoice_custom_fields_lines( $invoice, $template ){ +function jpcrm_invoicing_generate_invoice_custom_fields_lines( $invoice, $template ) { - global $zbs; + global $zbs; - $invoice_custom_fields_html = ''; + $invoice_custom_fields_html = ''; - // retrieve custom fields to pass through - $custom_fields_to_include = zeroBSCRM_getSetting( 'invcustomfields' ); - if ( !empty( $custom_fields_to_include ) ){ + // retrieve custom fields to pass through + $custom_fields_to_include = zeroBSCRM_getSetting( 'invcustomfields' ); + if ( ! empty( $custom_fields_to_include ) ) { - // split the csv - $custom_fields_to_include = array_map( 'trim', explode( ',', $custom_fields_to_include ) ); + // split the csv + $custom_fields_to_include = array_map( 'trim', explode( ',', $custom_fields_to_include ) ); - // retrieve fields - $invoice_custom_fields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_INVOICE ) ); + // retrieve fields + $invoice_custom_fields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_INVOICE ) ); - // build custom fields string. - // here we immitate what we expect the HTML to be, which will be errorsome if people modify heavily. - // for now it's better than no custom fields, let's see if people have issue with this approach. - foreach ( $invoice_custom_fields as $field_key => $field_info){ + // build custom fields string. + // here we immitate what we expect the HTML to be, which will be errorsome if people modify heavily. + // for now it's better than no custom fields, let's see if people have issue with this approach. + foreach ( $invoice_custom_fields as $field_key => $field_info ) { - // where user has set the field in settings - if ( in_array( $field_key, $custom_fields_to_include ) ){ + // where user has set the field in settings + if ( in_array( $field_key, $custom_fields_to_include ) ) { - $custom_field_str = ''; + $custom_field_str = ''; - if ( $invoice[ $field_key ] ){ + if ( $invoice[ $field_key ] ) { - $custom_field_str = $invoice[ $field_key ]; + $custom_field_str = $invoice[ $field_key ]; - // catch formatted dates - if ( isset( $invoice[ $field_key . '_cfdate' ] ) ){ + // catch formatted dates + if ( isset( $invoice[ $field_key . '_cfdate' ] ) ) { - $custom_field_str = $invoice[ $field_key . '_cfdate' ]; + $custom_field_str = $invoice[ $field_key . '_cfdate' ]; - } - } + } + } // skip empties if ( empty( $custom_field_str ) ) { @@ -1551,7 +1559,6 @@ function jpcrm_invoicing_generate_invoice_custom_fields_lines( $invoice, $templa return $invoice_custom_fields_html; } - // Used to generate specific part of invoice pdf: (Lineitem row in inv table) // phpcs:ignore Squiz.Commenting.FunctionComment.Missing function zeroBSCRM_invoicing_generateInvPart_lineitems( $invlines = array() ) { diff --git a/projects/plugins/crm/includes/ZeroBSCRM.List.Columns.php b/projects/plugins/crm/includes/ZeroBSCRM.List.Columns.php index d85c762b2e23..30e56cb81ec3 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.List.Columns.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.List.Columns.php @@ -1,417 +1,419 @@ - array('ID',false,'basefield'), - 'nameavatar' => array(__('Name and Avatar',"zero-bs-crm")), - //'email' => array('Email','zbsDefault_column_customeremail'), - 'status' => array(__('Status',"zero-bs-crm"),false,'basefield','editinline'=>1), - 'totalvalue' => array(__('Total Value',"zero-bs-crm")), - 'added' => array(__('Added',"zero-bs-crm"),false,'basefield') - ); - - $zeroBSCRM_columns_customer['all'] = array( - - 'id' => array('ID',false,'basefield'), - 'name' => array(__('Name',"zero-bs-crm"),false,'basefield'), - 'nameavatar' => array(__('Name and Avatar',"zero-bs-crm")), - 'email' => array(__('Email',"zero-bs-crm"),false,'basefield'), - 'status' => array(__('Status',"zero-bs-crm"),false,'basefield','editinline'=>1), - - 'hasquote' => array(__('Has Quote',"zero-bs-crm")), - 'hasinvoice' => array(__('Has Invoice',"zero-bs-crm")), - 'hastransaction' => array(__('Has Transaction',"zero-bs-crm")), - - 'quotecount' => array(__('Quote Count',"zero-bs-crm")), - 'invoicecount' => array(__('Invoice Count',"zero-bs-crm")), - 'transactioncount' => array(__('Transaction Count',"zero-bs-crm")), - - 'quotetotal' => array(__('Quotes Total',"zero-bs-crm")), - 'invoicetotal' => array(__('Invoices Total',"zero-bs-crm")), - 'transactiontotal' => array(__('Transactions Total',"zero-bs-crm")), - - 'totalvalue' => array(__('Total Value',"zero-bs-crm")), - - 'added' => array(__('Added',"zero-bs-crm"),false,'basefield'), - 'lastupdated' => array(__('Last Updated',"zero-bs-crm"),false,'basefield'), - 'assigned' => array(__('Assigned To',"zero-bs-crm"),false,'basefield','editinline'=>1), - 'latestlog' => array(__('Latest Log',"zero-bs-crm")), - 'tagged' => array(__('Tagged',"zero-bs-crm")), - 'editlink' => array(__('View',"zero-bs-crm")), - 'editdirectlink' => array(__('Edit',"zero-bs-crm")), - 'phonelink' => array(__('Phone Link',"zero-bs-crm")), - - 'lastcontacted' => array(__('Last Contacted',"zero-bs-crm")), - - 'company' => array(__('Company','zero-bs-crm')), - - ); - - /** - * Corrects label for 'Company' (could be Organisation) after the settings have loaded. - * Clunky workaround for now - */ - add_action( 'after_zerobscrm_settings_preinit', 'jpcrm_list_columns_correct_labels', 10); - function jpcrm_list_columns_correct_labels(){ - - global $zeroBSCRM_columns_customer; - - $zeroBSCRM_columns_customer['all']['company'] = array(jpcrm_label_company()); - - } - - /* ====================================================================================================== - ======================== / Customers - ===================================================================================================== */ - - /* ====================================================================================================== - ======================== Companies - ===================================================================================================== */ - - - global $zeroBSCRM_columns_company; - - $zeroBSCRM_columns_company = array(); - $zeroBSCRM_columns_company['default'] = array( - - - 'id' => array('ID',false,'basefield'), - 'name' => array(__('Name',"zero-bs-crm"),false,'basefield'), - 'status' => array(__('Status',"zero-bs-crm"),false,'basefield'), - 'contacts' => array(__('Contacts',"zero-bs-crm")), - 'added' => array(__('Added',"zero-bs-crm"),false,'basefield'), - 'viewlink' => array(__('View',"zero-bs-crm")) - ); - - $zeroBSCRM_columns_company['all'] = array( - - - 'id' => array('ID',false,'basefield'), - 'name' => array(__('Name',"zero-bs-crm"),false,'basefield'), - 'email' => array(__('Email',"zero-bs-crm"),false,'basefield'), - 'status' => array(__('Status',"zero-bs-crm"),false,'basefield'), - - - 'hasinvoice' => array(__('Has Invoice',"zero-bs-crm")), - 'hastransaction' => array(__('Has Transaction',"zero-bs-crm")), - - 'invoicecount' => array(__('Invoice Count',"zero-bs-crm")), - 'transactioncount' => array(__('Transaction Count',"zero-bs-crm")), - - 'invoicetotal' => array(__('Invoices Total',"zero-bs-crm")), - 'transactiontotal' => array(__('Transactions Total',"zero-bs-crm")), - - // When Company<->Quotes: - //'hasquote' => array(__('Has Quote',"zero-bs-crm")), - //'quotecount' => array(__('Quote Count',"zero-bs-crm")), - //'quotetotal' => array(__('Quotes Total',"zero-bs-crm")), - - 'totalvalue' => array(__('Total Value',"zero-bs-crm")), - - 'contacts' => array(__('Contacts',"zero-bs-crm")), - 'added' => array(__('Added',"zero-bs-crm"),false,'basefield'), - 'lastupdated' => array(__('Last Updated',"zero-bs-crm"),false,'basefield'), - 'viewlink' => array(__('View',"zero-bs-crm")), - 'editlink' => array(__('Edit',"zero-bs-crm")), - 'assigned' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), - 'tagged' => array(__(__('Tagged',"zero-bs-crm"),"zero-bs-crm")), - 'phonelink' => array(__('Phone Link',"zero-bs-crm")), - // Should this be in company? (removed 04/9/18, don't think wired up) ''latestlog' => array(__('Latest Log',"zero-bs-crm")), - // Should this be in company? (removed 04/9/18, don't think wired up) 'lastcontacted' => array(__('Last Contacted',"zero-bs-crm")), - - ); - - /* ====================================================================================================== - ======================== / Companies - ===================================================================================================== */ - - /* ====================================================================================================== - ======================== Quotes - ===================================================================================================== */ - - - global $zeroBSCRM_columns_quote; - - $zeroBSCRM_columns_quote = array(); - $zeroBSCRM_columns_quote['default'] = array( - 'id' => array('ID',false,'basefield'), - 'title' => array(__('Quote Title','zero-bs-crm'),false,'basefield'), + #{ Wh NOTE: this should all be in 1 global, messy to ahve them all separate! } + +/* +====================================================== + Hard Coded Columns for each list view (UI2.0) + (Defaults which can be overriden by custom views) + ====================================================== */ + + /* + // LABEL, column ??, grouping (in column manager) + array('LABEL','zbsDefault_column_customerid','basefield') + + */ + + /* + ====================================================================================================== + ======================== Customers + ===================================================================================================== */ + + global $zeroBSCRM_columns_customer; + + $zeroBSCRM_columns_customer = array(); + $zeroBSCRM_columns_customer['default'] = array( + + 'id' => array( 'ID', false, 'basefield' ), + 'nameavatar' => array( __( 'Name and Avatar', 'zero-bs-crm' ) ), + // 'email' => array('Email','zbsDefault_column_customeremail'), + 'status' => array( + __( 'Status', 'zero-bs-crm' ), + false, + 'basefield', + 'editinline' => 1, + ), + 'totalvalue' => array( __( 'Total Value', 'zero-bs-crm' ) ), + 'added' => array( __( 'Added', 'zero-bs-crm' ), false, 'basefield' ), + ); + + $zeroBSCRM_columns_customer['all'] = array( + + 'id' => array( 'ID', false, 'basefield' ), + 'name' => array( __( 'Name', 'zero-bs-crm' ), false, 'basefield' ), + 'nameavatar' => array( __( 'Name and Avatar', 'zero-bs-crm' ) ), + 'email' => array( __( 'Email', 'zero-bs-crm' ), false, 'basefield' ), + 'status' => array( + __( 'Status', 'zero-bs-crm' ), + false, + 'basefield', + 'editinline' => 1, + ), + + 'hasquote' => array( __( 'Has Quote', 'zero-bs-crm' ) ), + 'hasinvoice' => array( __( 'Has Invoice', 'zero-bs-crm' ) ), + 'hastransaction' => array( __( 'Has Transaction', 'zero-bs-crm' ) ), + + 'quotecount' => array( __( 'Quote Count', 'zero-bs-crm' ) ), + 'invoicecount' => array( __( 'Invoice Count', 'zero-bs-crm' ) ), + 'transactioncount' => array( __( 'Transaction Count', 'zero-bs-crm' ) ), + + 'quotetotal' => array( __( 'Quotes Total', 'zero-bs-crm' ) ), + 'invoicetotal' => array( __( 'Invoices Total', 'zero-bs-crm' ) ), + 'transactiontotal' => array( __( 'Transactions Total', 'zero-bs-crm' ) ), + + 'totalvalue' => array( __( 'Total Value', 'zero-bs-crm' ) ), + + 'added' => array( __( 'Added', 'zero-bs-crm' ), false, 'basefield' ), + 'lastupdated' => array( __( 'Last Updated', 'zero-bs-crm' ), false, 'basefield' ), + 'assigned' => array( + __( 'Assigned To', 'zero-bs-crm' ), + false, + 'basefield', + 'editinline' => 1, + ), + 'latestlog' => array( __( 'Latest Log', 'zero-bs-crm' ) ), + 'tagged' => array( __( 'Tagged', 'zero-bs-crm' ) ), + 'editlink' => array( __( 'View', 'zero-bs-crm' ) ), + 'editdirectlink' => array( __( 'Edit', 'zero-bs-crm' ) ), + 'phonelink' => array( __( 'Phone Link', 'zero-bs-crm' ) ), + + 'lastcontacted' => array( __( 'Last Contacted', 'zero-bs-crm' ) ), + + 'company' => array( __( 'Company', 'zero-bs-crm' ) ), + + ); + + /** + * Corrects label for 'Company' (could be Organisation) after the settings have loaded. + * Clunky workaround for now + */ + add_action( 'after_zerobscrm_settings_preinit', 'jpcrm_list_columns_correct_labels', 10 ); + function jpcrm_list_columns_correct_labels() { + + global $zeroBSCRM_columns_customer; + + $zeroBSCRM_columns_customer['all']['company'] = array( jpcrm_label_company() ); + } + + /* + ====================================================================================================== + ======================== / Customers + ===================================================================================================== */ + + /* + ====================================================================================================== + ======================== Companies + ===================================================================================================== */ + + global $zeroBSCRM_columns_company; + + $zeroBSCRM_columns_company = array(); + $zeroBSCRM_columns_company['default'] = array( + + 'id' => array( 'ID', false, 'basefield' ), + 'name' => array( __( 'Name', 'zero-bs-crm' ), false, 'basefield' ), + 'status' => array( __( 'Status', 'zero-bs-crm' ), false, 'basefield' ), + 'contacts' => array( __( 'Contacts', 'zero-bs-crm' ) ), + 'added' => array( __( 'Added', 'zero-bs-crm' ), false, 'basefield' ), + 'viewlink' => array( __( 'View', 'zero-bs-crm' ) ), + ); + + $zeroBSCRM_columns_company['all'] = array( + + 'id' => array( 'ID', false, 'basefield' ), + 'name' => array( __( 'Name', 'zero-bs-crm' ), false, 'basefield' ), + 'email' => array( __( 'Email', 'zero-bs-crm' ), false, 'basefield' ), + 'status' => array( __( 'Status', 'zero-bs-crm' ), false, 'basefield' ), + + 'hasinvoice' => array( __( 'Has Invoice', 'zero-bs-crm' ) ), + 'hastransaction' => array( __( 'Has Transaction', 'zero-bs-crm' ) ), + + 'invoicecount' => array( __( 'Invoice Count', 'zero-bs-crm' ) ), + 'transactioncount' => array( __( 'Transaction Count', 'zero-bs-crm' ) ), + + 'invoicetotal' => array( __( 'Invoices Total', 'zero-bs-crm' ) ), + 'transactiontotal' => array( __( 'Transactions Total', 'zero-bs-crm' ) ), + + // When Company<->Quotes: + // 'hasquote' => array(__('Has Quote',"zero-bs-crm")), + // 'quotecount' => array(__('Quote Count',"zero-bs-crm")), + // 'quotetotal' => array(__('Quotes Total',"zero-bs-crm")), + + 'totalvalue' => array( __( 'Total Value', 'zero-bs-crm' ) ), + + 'contacts' => array( __( 'Contacts', 'zero-bs-crm' ) ), + 'added' => array( __( 'Added', 'zero-bs-crm' ), false, 'basefield' ), + 'lastupdated' => array( __( 'Last Updated', 'zero-bs-crm' ), false, 'basefield' ), + 'viewlink' => array( __( 'View', 'zero-bs-crm' ) ), + 'editlink' => array( __( 'Edit', 'zero-bs-crm' ) ), + 'assigned' => array( __( 'Assigned To', 'zero-bs-crm' ), false, 'basefield' ), + 'tagged' => array( __( __( 'Tagged', 'zero-bs-crm' ), 'zero-bs-crm' ) ), + 'phonelink' => array( __( 'Phone Link', 'zero-bs-crm' ) ), + // Should this be in company? (removed 04/9/18, don't think wired up) ''latestlog' => array(__('Latest Log',"zero-bs-crm")), + // Should this be in company? (removed 04/9/18, don't think wired up) 'lastcontacted' => array(__('Last Contacted',"zero-bs-crm")), + + ); + + /* + ====================================================================================================== + ======================== / Companies + ===================================================================================================== */ + + /* + ====================================================================================================== + ======================== Quotes + ===================================================================================================== */ + + global $zeroBSCRM_columns_quote; + + $zeroBSCRM_columns_quote = array(); + $zeroBSCRM_columns_quote['default'] = array( + 'id' => array( 'ID', false, 'basefield' ), + 'title' => array( __( 'Quote Title', 'zero-bs-crm' ), false, 'basefield' ), 'customer' => array( __( 'Contact', 'zero-bs-crm' ) ), // phpcs:ignore WordPress.Arrays.ArrayIndentation.ItemNotAligned -- impossible to fix without fixing everything else. - 'status' => array(__('Status','zero-bs-crm'),false,'basefield'), - 'value' => array(__('Quote Value',"zero-bs-crm"),false,'basefield'), - 'editlink' => array(__('Edit',"zero-bs-crm")) - + 'status' => array( __( 'Status', 'zero-bs-crm' ), false, 'basefield' ), + 'value' => array( __( 'Quote Value', 'zero-bs-crm' ), false, 'basefield' ), + 'editlink' => array( __( 'Edit', 'zero-bs-crm' ) ), - ); + ); - $zeroBSCRM_columns_quote['all'] = array( - 'id' => array('ID',false,'basefield'), - 'title' => array(__('Quote Title','zero-bs-crm'),false,'basefield'), + $zeroBSCRM_columns_quote['all'] = array( + 'id' => array( 'ID', false, 'basefield' ), + 'title' => array( __( 'Quote Title', 'zero-bs-crm' ), false, 'basefield' ), 'customer' => array( __( 'Contact', 'zero-bs-crm' ) ), // phpcs:ignore WordPress.Arrays.ArrayIndentation.ItemNotAligned -- impossible to fix without fixing everything else. - 'status' => array(__('Status','zero-bs-crm'),false,'basefield'), - 'value' => array(__('Quote Value',"zero-bs-crm"),false,'basefield'), - 'editlink' => array(__('Edit',"zero-bs-crm")), - // not user-configurable, so disabling for now - //'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), - ); - - /* ====================================================================================================== - ======================== / Quotes - ===================================================================================================== */ + 'status' => array( __( 'Status', 'zero-bs-crm' ), false, 'basefield' ), + 'value' => array( __( 'Quote Value', 'zero-bs-crm' ), false, 'basefield' ), + 'editlink' => array( __( 'Edit', 'zero-bs-crm' ) ), + // not user-configurable, so disabling for now + // 'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), + ); + /* + ====================================================================================================== + ======================== / Quotes + ===================================================================================================== */ - /* ====================================================================================================== - ======================== Invoices - ===================================================================================================== */ + /* + ====================================================================================================== + ======================== Invoices + ===================================================================================================== */ - - global $zeroBSCRM_columns_invoice; + global $zeroBSCRM_columns_invoice; - $zeroBSCRM_columns_invoice = array(); - $zeroBSCRM_columns_invoice['default'] = array( - 'id' => array('ID',false,'basefield'), + $zeroBSCRM_columns_invoice = array(); + $zeroBSCRM_columns_invoice['default'] = array( + 'id' => array( 'ID', false, 'basefield' ), - 'ref' => array(__('Reference','zero-bs-crm'),false,'basefield'), + 'ref' => array( __( 'Reference', 'zero-bs-crm' ), false, 'basefield' ), 'customer' => array( __( 'Contact', 'zero-bs-crm' ) ), // phpcs:ignore WordPress.Arrays.ArrayIndentation.ItemNotAligned -- impossible to fix without fixing everything else. - 'status' => array(__('Status','zero-bs-crm'),false,'basefield'), - 'value' => array(__('Value',"zero-bs-crm"),false,'basefield'), - 'date' => array(__('Date',"zero-bs-crm"),false,'basefield'), - 'editlink' => array(__('Edit',"zero-bs-crm")) - ); + 'status' => array( __( 'Status', 'zero-bs-crm' ), false, 'basefield' ), + 'value' => array( __( 'Value', 'zero-bs-crm' ), false, 'basefield' ), + 'date' => array( __( 'Date', 'zero-bs-crm' ), false, 'basefield' ), + 'editlink' => array( __( 'Edit', 'zero-bs-crm' ) ), + ); $zeroBSCRM_columns_invoice['all'] = array( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,Generic.WhiteSpace.ScopeIndent.Incorrect - 'id' => array('ID',false,'basefield'), - 'ref' => array(__('Reference','zero-bs-crm'),false,'basefield'), + 'id' => array( 'ID', false, 'basefield' ), + 'ref' => array( __( 'Reference', 'zero-bs-crm' ), false, 'basefield' ), 'customer' => array( __( 'Contact', 'zero-bs-crm' ) ), // phpcs:ignore WordPress.Arrays.ArrayIndentation.ItemNotAligned -- impossible to fix without fixing everything else. - 'status' => array(__('Status','zero-bs-crm'),false,'basefield'), - 'value' => array(__('Value',"zero-bs-crm"),false,'basefield'), - 'date' => array(__('Date',"zero-bs-crm"),false,'basefield'), - 'due' => array(__('Due date',"zero-bs-crm"),false,'basefield'), - - 'editlink' => array(__('Edit',"zero-bs-crm")), + 'status' => array( __( 'Status', 'zero-bs-crm' ), false, 'basefield' ), + 'value' => array( __( 'Value', 'zero-bs-crm' ), false, 'basefield' ), + 'date' => array( __( 'Date', 'zero-bs-crm' ), false, 'basefield' ), + 'due' => array( __( 'Due date', 'zero-bs-crm' ), false, 'basefield' ), - // not user-configurable, so disabling for now - //'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), + 'editlink' => array( __( 'Edit', 'zero-bs-crm' ) ), - ); + // not user-configurable, so disabling for now + // 'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), + ); - /* ====================================================================================================== - ======================== / Invoices - ===================================================================================================== */ + /* + ====================================================================================================== + ======================== / Invoices + ===================================================================================================== */ + /* + ====================================================================================================== + ======================== Transactions + ===================================================================================================== */ + global $zeroBSCRM_columns_transaction; -/* ====================================================================================================== - ======================== Transactions - ===================================================================================================== */ - - - global $zeroBSCRM_columns_transaction; - - $zeroBSCRM_columns_transaction = array(); + $zeroBSCRM_columns_transaction = array(); $zeroBSCRM_columns_transaction['default'] = array( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - 'id' => array('ID','zbsDefault_column_customerid','basefield'), + 'id' => array( 'ID', 'zbsDefault_column_customerid', 'basefield' ), 'customer' => array( __( 'Contact', 'zero-bs-crm' ) ), // phpcs:ignore WordPress.Arrays.ArrayIndentation.ItemNotAligned -- impossible to fix without fixing everything else. - 'status' => array(__('Status',"zero-bs-crm"),false,'basefield'), - 'total' => array(__('Value',"zero-bs-crm"),false,'basefield'), - 'item' => array(__('Item',"zero-bs-crm"),false,'basefield'), - 'added' => array(__('Added',"zero-bs-crm"),false,'basefield'), - 'editlink' => array(__('Edit Link',"zero-bs-crm")) + 'status' => array( __( 'Status', 'zero-bs-crm' ), false, 'basefield' ), + 'total' => array( __( 'Value', 'zero-bs-crm' ), false, 'basefield' ), + 'item' => array( __( 'Item', 'zero-bs-crm' ), false, 'basefield' ), + 'added' => array( __( 'Added', 'zero-bs-crm' ), false, 'basefield' ), + 'editlink' => array( __( 'Edit Link', 'zero-bs-crm' ) ), - ); + ); - $zeroBSCRM_columns_transaction['all'] = array( - 'id' => array('ID','zbsDefault_column_customerid','basefield'), + $zeroBSCRM_columns_transaction['all'] = array( + 'id' => array( 'ID', 'zbsDefault_column_customerid', 'basefield' ), 'customer' => array( __( 'Contact', 'zero-bs-crm' ) ), // phpcs:ignore WordPress.Arrays.ArrayIndentation.ItemNotAligned -- impossible to fix without fixing everything else. - 'customeremail' => array(__('Email',"zero-bs-crm")), - 'tagged' => array(__(__('Tagged',"zero-bs-crm"),"zero-bs-crm")), - 'status' => array(__('Status',"zero-bs-crm"),false,'basefield'), - 'total' => array(__('Value',"zero-bs-crm"),false,'basefield'), - 'item' => array(__('Item',"zero-bs-crm"),false,'basefield'), - - 'added' => array(__('Added',"zero-bs-crm"),false,'basefield'), - 'editlink' => array(__('Edit Link',"zero-bs-crm")), - 'external_source' => array(__('External Source',"zero-bs-crm")), - - // not user-configurable, so disabling for now - //'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), - - ); - - /* ====================================================================================================== - ======================== / Transactions - ===================================================================================================== */ - - -/* ====================================================================================================== - ======================== Forms - ===================================================================================================== */ - - - global $zeroBSCRM_columns_form; - - $zeroBSCRM_columns_form = array(); - $zeroBSCRM_columns_form['default'] = array( - 'id' => array('ID',false,'basefield'), - 'title' => array(__('Title','zero-bs-crm'),false,'basefield'), - 'style' => array(__('Style',"zero-bs-crm"),false,'basefield'), - 'views' => array(__('Views',"zero-bs-crm")), - 'conversions' => array(__('Conversions',"zero-bs-crm")), - 'added' => array(__('Added',"zero-bs-crm"),false,'basefield'), - 'editlink' => array(__('Edit',"zero-bs-crm")) - ); + 'customeremail' => array( __( 'Email', 'zero-bs-crm' ) ), + 'tagged' => array( __( __( 'Tagged', 'zero-bs-crm' ), 'zero-bs-crm' ) ), + 'status' => array( __( 'Status', 'zero-bs-crm' ), false, 'basefield' ), + 'total' => array( __( 'Value', 'zero-bs-crm' ), false, 'basefield' ), + 'item' => array( __( 'Item', 'zero-bs-crm' ), false, 'basefield' ), - $zeroBSCRM_columns_form['all'] = array( - 'id' => array('ID',false,'basefield'), - 'title' => array(__('Title','zero-bs-crm'),false,'basefield'), - 'style' => array(__('Style',"zero-bs-crm"),false,'basefield'), - 'views' => array(__('Views',"zero-bs-crm")), - 'conversions' => array(__('Conversions',"zero-bs-crm")), - 'added' => array(__('Added',"zero-bs-crm"),false,'basefield'), - 'editlink' => array(__('Edit',"zero-bs-crm")) - ); - - /* ====================================================================================================== - ======================== / Forms - ===================================================================================================== */ + 'added' => array( __( 'Added', 'zero-bs-crm' ), false, 'basefield' ), + 'editlink' => array( __( 'Edit Link', 'zero-bs-crm' ) ), + 'external_source' => array( __( 'External Source', 'zero-bs-crm' ) ), - /* ====================================================================================================== - ======================== Segments - ===================================================================================================== */ - - - global $zeroBSCRM_columns_segment; - - $zeroBSCRM_columns_segment = array(); - $zeroBSCRM_columns_segment['default'] = array( - 'id' => array('ID',false,'basefield'), - 'name' => array(__('Name','zero-bs-crm'),false,'basefield'), - 'audiencecount' => array(__('Contact Count','zero-bs-crm')), - 'action' => array(__('Action','zero-bs-crm')) - ); - - $zeroBSCRM_columns_segment['all'] = array( - 'id' => array('ID',false,'basefield'), - 'name' => array(__('Name','zero-bs-crm'),false,'basefield'), - 'audiencecount' => array(__('Contact Count','zero-bs-crm')), - 'action' => array(__('Action','zero-bs-crm')), - 'added' => array(__('Added','zero-bs-crm')) - - ); - - - - /* ====================================================================================================== - ======================== / Segments - ===================================================================================================== */ - - /* ====================================================================================================== - ======================== Quote Templates - ===================================================================================================== */ - - - global $zeroBSCRM_columns_quotetemplate; - - $zeroBSCRM_columns_quotetemplate = array(); - $zeroBSCRM_columns_quotetemplate['default'] = array( - - - 'id' => array('ID',false,'basefield'), - 'title' => array(__('Title','zero-bs-crm'),false,'basefield'), - 'action' => array(__('Action','zero-bs-crm')) - ); - - $zeroBSCRM_columns_quotetemplate['all'] = array( - - - 'id' => array('ID',false,'basefield'), - 'title' => array(__('Title','zero-bs-crm'),false,'basefield'), - 'action' => array(__('Action','zero-bs-crm')) - - ); - - - - /* ====================================================================================================== - ======================== / Quote Templates - ===================================================================================================== */ - - /* ====================================================================================================== - ======================== Tasks - ===================================================================================================== */ - - - global $zeroBSCRM_columns_event; - - $zeroBSCRM_columns_event = array(); - $zeroBSCRM_columns_event['default'] = array( - - - 'id' => array('ID',false,'basefield'), - 'title' => array( __('Name','zero-bs-crm'), false, 'basefield' ), - 'start' => array( __('Starting', 'zero-bs-crm' ) ), - 'end' => array( __('Finishing', 'zero-bs-crm' ) ), - 'status' => array( __('Status', 'zero-bs-crm' ) ), - 'assigned' => array(__('Assigned To',"zero-bs-crm"), false, 'basefield' ), - 'action' => array( __('Action', 'zero-bs-crm') ) - ); - - $zeroBSCRM_columns_event['all'] = array( - - 'id' => array('ID',false,'basefield'), - 'title' => array( __('Name','zero-bs-crm'), false, 'basefield' ), - 'desc' => array( __('Description', 'zero-bs-crm' ) ), - 'start' => array( __('Starting', 'zero-bs-crm' ) ), - 'end' => array( __('Finishing', 'zero-bs-crm' ) ), - 'status' => array( __('Status', 'zero-bs-crm' ) ), - 'remind' => array( __('Reminder', 'zero-bs-crm' ) ), - 'showcal' => array( __('Show on Cal', 'zero-bs-crm' ) ), - //'showportal' => array( __('Show on Portal', 'zero-bs-crm' ) ), - 'contact' => array( __('Contact', 'zero-bs-crm' ) ), - 'company' => array( __('Company', 'zero-bs-crm' ) ), - 'assigned' => array(__('Assigned To',"zero-bs-crm"), false, 'basefield' ), - 'action' => array( __('Action', 'zero-bs-crm') ) - - ); - - - - /* ====================================================================================================== - ======================== / Tasks - ===================================================================================================== */ + // not user-configurable, so disabling for now + // 'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), + + ); + + /* + ====================================================================================================== + ======================== / Transactions + ===================================================================================================== */ + + /* + ====================================================================================================== + ======================== Forms + ===================================================================================================== */ + + global $zeroBSCRM_columns_form; + + $zeroBSCRM_columns_form = array(); + $zeroBSCRM_columns_form['default'] = array( + 'id' => array( 'ID', false, 'basefield' ), + 'title' => array( __( 'Title', 'zero-bs-crm' ), false, 'basefield' ), + 'style' => array( __( 'Style', 'zero-bs-crm' ), false, 'basefield' ), + 'views' => array( __( 'Views', 'zero-bs-crm' ) ), + 'conversions' => array( __( 'Conversions', 'zero-bs-crm' ) ), + 'added' => array( __( 'Added', 'zero-bs-crm' ), false, 'basefield' ), + 'editlink' => array( __( 'Edit', 'zero-bs-crm' ) ), + ); + + $zeroBSCRM_columns_form['all'] = array( + 'id' => array( 'ID', false, 'basefield' ), + 'title' => array( __( 'Title', 'zero-bs-crm' ), false, 'basefield' ), + 'style' => array( __( 'Style', 'zero-bs-crm' ), false, 'basefield' ), + 'views' => array( __( 'Views', 'zero-bs-crm' ) ), + 'conversions' => array( __( 'Conversions', 'zero-bs-crm' ) ), + 'added' => array( __( 'Added', 'zero-bs-crm' ), false, 'basefield' ), + 'editlink' => array( __( 'Edit', 'zero-bs-crm' ) ), + ); + + /* + ====================================================================================================== + ======================== / Forms + ===================================================================================================== */ + + /* + ====================================================================================================== + ======================== Segments + ===================================================================================================== */ + + global $zeroBSCRM_columns_segment; + + $zeroBSCRM_columns_segment = array(); + $zeroBSCRM_columns_segment['default'] = array( + 'id' => array( 'ID', false, 'basefield' ), + 'name' => array( __( 'Name', 'zero-bs-crm' ), false, 'basefield' ), + 'audiencecount' => array( __( 'Contact Count', 'zero-bs-crm' ) ), + 'action' => array( __( 'Action', 'zero-bs-crm' ) ), + ); + + $zeroBSCRM_columns_segment['all'] = array( + 'id' => array( 'ID', false, 'basefield' ), + 'name' => array( __( 'Name', 'zero-bs-crm' ), false, 'basefield' ), + 'audiencecount' => array( __( 'Contact Count', 'zero-bs-crm' ) ), + 'action' => array( __( 'Action', 'zero-bs-crm' ) ), + 'added' => array( __( 'Added', 'zero-bs-crm' ) ), + + ); + + /* + ====================================================================================================== + ======================== / Segments + ===================================================================================================== */ + + /* + ====================================================================================================== + ======================== Quote Templates + ===================================================================================================== */ + + global $zeroBSCRM_columns_quotetemplate; + + $zeroBSCRM_columns_quotetemplate = array(); + $zeroBSCRM_columns_quotetemplate['default'] = array( + + 'id' => array( 'ID', false, 'basefield' ), + 'title' => array( __( 'Title', 'zero-bs-crm' ), false, 'basefield' ), + 'action' => array( __( 'Action', 'zero-bs-crm' ) ), + ); + + $zeroBSCRM_columns_quotetemplate['all'] = array( + + 'id' => array( 'ID', false, 'basefield' ), + 'title' => array( __( 'Title', 'zero-bs-crm' ), false, 'basefield' ), + 'action' => array( __( 'Action', 'zero-bs-crm' ) ), + + ); + + /* + ====================================================================================================== + ======================== / Quote Templates + ===================================================================================================== */ + + /* + ====================================================================================================== + ======================== Tasks + ===================================================================================================== */ + + global $zeroBSCRM_columns_event; + + $zeroBSCRM_columns_event = array(); + $zeroBSCRM_columns_event['default'] = array( + + 'id' => array( 'ID', false, 'basefield' ), + 'title' => array( __( 'Name', 'zero-bs-crm' ), false, 'basefield' ), + 'start' => array( __( 'Starting', 'zero-bs-crm' ) ), + 'end' => array( __( 'Finishing', 'zero-bs-crm' ) ), + 'status' => array( __( 'Status', 'zero-bs-crm' ) ), + 'assigned' => array( __( 'Assigned To', 'zero-bs-crm' ), false, 'basefield' ), + 'action' => array( __( 'Action', 'zero-bs-crm' ) ), + ); + + $zeroBSCRM_columns_event['all'] = array( + + 'id' => array( 'ID', false, 'basefield' ), + 'title' => array( __( 'Name', 'zero-bs-crm' ), false, 'basefield' ), + 'desc' => array( __( 'Description', 'zero-bs-crm' ) ), + 'start' => array( __( 'Starting', 'zero-bs-crm' ) ), + 'end' => array( __( 'Finishing', 'zero-bs-crm' ) ), + 'status' => array( __( 'Status', 'zero-bs-crm' ) ), + 'remind' => array( __( 'Reminder', 'zero-bs-crm' ) ), + 'showcal' => array( __( 'Show on Cal', 'zero-bs-crm' ) ), + // 'showportal' => array( __('Show on Portal', 'zero-bs-crm' ) ), + 'contact' => array( __( 'Contact', 'zero-bs-crm' ) ), + 'company' => array( __( 'Company', 'zero-bs-crm' ) ), + 'assigned' => array( __( 'Assigned To', 'zero-bs-crm' ), false, 'basefield' ), + 'action' => array( __( 'Action', 'zero-bs-crm' ) ), + + ); + + /* + ====================================================================================================== + ======================== / Tasks + ===================================================================================================== */ // phpcs:disable Generic.WhiteSpace.ScopeIndent.Incorrect, Generic.WhiteSpace.ScopeIndent.IncorrectExact /** @@ -419,90 +421,96 @@ function jpcrm_list_columns_correct_labels(){ */ function zeroBSCRM_unpackListViewSettings() { - // ALL FIELD TYPES - global $zeroBSCRM_columns_customer, $zbsCustomerFields; - global $zeroBSCRM_columns_company, $zbsCompanyFields; - global $zeroBSCRM_columns_quote, $zbsCustomerQuoteFields; - global $zeroBSCRM_columns_invoice, $zbsCustomerInvoiceFields; - global $zeroBSCRM_columns_transaction, $zbsTransactionFields; - global $zeroBSCRM_columns_form, $zbsFormFields; + // ALL FIELD TYPES + global $zeroBSCRM_columns_customer, $zbsCustomerFields; + global $zeroBSCRM_columns_company, $zbsCompanyFields; + global $zeroBSCRM_columns_quote, $zbsCustomerQuoteFields; + global $zeroBSCRM_columns_invoice, $zbsCustomerInvoiceFields; + global $zeroBSCRM_columns_transaction, $zbsTransactionFields; + global $zeroBSCRM_columns_form, $zbsFormFields; - $useSecondAddress = zeroBSCRM_getSetting('secondaddress'); - $second_address_label = zeroBSCRM_getSetting( 'secondaddresslabel' ); - if ( empty( $second_address_label ) ) { - $second_address_label = __( 'Second Address', 'zero-bs-crm' ); - } + $useSecondAddress = zeroBSCRM_getSetting( 'secondaddress' ); + $second_address_label = zeroBSCRM_getSetting( 'secondaddresslabel' ); + if ( empty( $second_address_label ) ) { + $second_address_label = __( 'Second Address', 'zero-bs-crm' ); + } - // Cycle through each + add - $mappings = array( + // Cycle through each + add + $mappings = array( - 'zeroBSCRM_columns_customer' => 'zbsCustomerFields', - 'zeroBSCRM_columns_company' => 'zbsCompanyFields', - 'zeroBSCRM_columns_quote' => 'zbsCustomerQuoteFields', // not sure why naming convention lost here - 'zeroBSCRM_columns_invoice' => 'zbsCustomerInvoiceFields', // not sure why naming convention lost here - 'zeroBSCRM_columns_transaction' => 'zbsTransactionFields', - 'zeroBSCRM_columns_form' => 'zbsFormFields', + 'zeroBSCRM_columns_customer' => 'zbsCustomerFields', + 'zeroBSCRM_columns_company' => 'zbsCompanyFields', + 'zeroBSCRM_columns_quote' => 'zbsCustomerQuoteFields', // not sure why naming convention lost here + 'zeroBSCRM_columns_invoice' => 'zbsCustomerInvoiceFields', // not sure why naming convention lost here + 'zeroBSCRM_columns_transaction' => 'zbsTransactionFields', + 'zeroBSCRM_columns_form' => 'zbsFormFields', - ); + ); - foreach ($mappings as $columnsObjName => $fieldsObjName){ + foreach ( $mappings as $columnsObjName => $fieldsObjName ) { - // add all normal fields to columns (DAL2) from 2.95 - if (is_array(${$fieldsObjName}) && count(${$fieldsObjName}) > 0){ - foreach (${$fieldsObjName} as $fKey => $fDetail){ - if (!isset(${$columnsObjName}['all'][$fKey])){ + // add all normal fields to columns (DAL2) from 2.95 + if ( is_array( ${$fieldsObjName} ) && count( ${$fieldsObjName} ) > 0 ) { + foreach ( ${$fieldsObjName} as $fKey => $fDetail ) { + if ( ! isset( ${$columnsObjName}['all'][ $fKey ] ) ) { - // some need hiding (just for api/behind scenes:) - $hideCol = false; if (is_array($fDetail) && isset($fDetail['nocolumn']) && $fDetail['nocolumn']) $hideCol = true; + // some need hiding (just for api/behind scenes:) + $hideCol = false; + if ( is_array( $fDetail ) && isset( $fDetail['nocolumn'] ) && $fDetail['nocolumn'] ) { + $hideCol = true; + } - if (!$hideCol){ + if ( ! $hideCol ) { - $skip = false; // skip addr 2 if off + $skip = false; // skip addr 2 if off - // add it - $cfTitle = $fKey; if (is_array($fDetail) && isset($fDetail[1])) $cfTitle = $fDetail[1]; + // add it + $cfTitle = $fKey; + if ( is_array( $fDetail ) && isset( $fDetail[1] ) ) { + $cfTitle = $fDetail[1]; + } - // secaddr get's dealt with: + // secaddr get's dealt with: if ( str_starts_with( $fKey, 'secaddr_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $cfTitle .= ' (' . esc_html( $second_address_label ) . ')'; - if ($useSecondAddress !== 1) $skip = true; - } - - if (!$skip) ${$columnsObjName}['all'][$fKey] = array($cfTitle,false,'basefield'); // note adding as basefield :) - } - - } - } - } - - } - - // Auto-add 'edit link' to quotes invs (somehow it wasn't always adding) - $customviews2 = zeroBSCRM_getSetting('customviews2'); $cv2Changed = false; - if (isset($customviews2['quote']) && !array_key_exists('editlink', $customviews2['quote'])){ - - // add it - $customviews2['quote']['editlink'] = array(__('Edit',"zero-bs-crm")); - $cv2Changed = true; - - } - if (isset($customviews2['invoice']) && !array_key_exists('editlink', $customviews2['invoice'])){ - - // add it - $customviews2['invoice']['editlink'] = array(__('Edit',"zero-bs-crm")); - $cv2Changed = true; - - } - if ($cv2Changed && is_array($customviews2)){ - - // Save setting - global $zbs; - return $zbs->settings->update('customviews2',$customviews2); - - - } - - - } + $cfTitle .= ' (' . esc_html( $second_address_label ) . ')'; + if ( $useSecondAddress !== 1 ) { + $skip = true; + } + } + + if ( ! $skip ) { + ${$columnsObjName}['all'][ $fKey ] = array( $cfTitle, false, 'basefield' ); // note adding as basefield :) + } + } + } + } + } + } + + // Auto-add 'edit link' to quotes invs (somehow it wasn't always adding) + $customviews2 = zeroBSCRM_getSetting( 'customviews2' ); + $cv2Changed = false; + if ( isset( $customviews2['quote'] ) && ! array_key_exists( 'editlink', $customviews2['quote'] ) ) { + + // add it + $customviews2['quote']['editlink'] = array( __( 'Edit', 'zero-bs-crm' ) ); + $cv2Changed = true; + + } + if ( isset( $customviews2['invoice'] ) && ! array_key_exists( 'editlink', $customviews2['invoice'] ) ) { + + // add it + $customviews2['invoice']['editlink'] = array( __( 'Edit', 'zero-bs-crm' ) ); + $cv2Changed = true; + + } + if ( $cv2Changed && is_array( $customviews2 ) ) { + + // Save setting + global $zbs; + return $zbs->settings->update( 'customviews2', $customviews2 ); + + } + } // phpcs:enable Generic.WhiteSpace.ScopeIndent.Incorrect, Generic.WhiteSpace.ScopeIndent.IncorrectExact diff --git a/projects/plugins/crm/includes/ZeroBSCRM.List.php b/projects/plugins/crm/includes/ZeroBSCRM.List.php index aeaa6e76a851..d6a73f939c3c 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.List.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.List.php @@ -1,5 +1,6 @@ -objType) || empty($this->postType) || empty($this->postPage) || empty($this->singular) || empty($this->plural)){ + if ( empty( $this->objType ) || empty( $this->postType ) || empty( $this->postPage ) || empty( $this->singular ) || empty( $this->plural ) ) { - return 'Error.'; - } - - global $zbs; + return 'Error.'; + } + global $zbs; - #} Retrieve all passed filters (tags, etc.) - $listViewFilters = array(); if (isset($_GET['zbs_tag'])){ + #} Retrieve all passed filters (tags, etc.) + $listViewFilters = array(); if ( isset( $_GET['zbs_tag'] ) ) { - $possibleTag = (int)sanitize_text_field($_GET['zbs_tag']); + $possibleTag = (int) sanitize_text_field( $_GET['zbs_tag'] ); $possibleTagObj = $zbs->DAL->getTag( $possibleTag, array( 'objtype' => $this->objTypeID ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase if ( isset( $possibleTagObj['id'] ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $listViewFilters['tags'] = array( $possibleTagObj ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - } - if (isset($_GET['s']) && !empty($_GET['s'])){ + } + if ( isset( $_GET['s'] ) && ! empty( $_GET['s'] ) ) { - $listViewFilters['s'] = sanitize_text_field($_GET['s']); + $listViewFilters['s'] = sanitize_text_field( $_GET['s'] ); - } - if (isset($_GET['quickfilters']) && !empty($_GET['quickfilters'])){ + } + if ( isset( $_GET['quickfilters'] ) && ! empty( $_GET['quickfilters'] ) ) { - // set it whether legit? what'll this do on error urls people make up? - // v2.2+ hone this + add multi-filter - // v2.99.5 - ALWAYS lowercase :) + // set it whether legit? what'll this do on error urls people make up? + // v2.2+ hone this + add multi-filter + // v2.99.5 - ALWAYS lowercase :) $possible_quick_filters = sanitize_text_field( $_GET['quickfilters'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash $listViewFilters['quickfilters'] = array( $possible_quick_filters ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } - - - #} Paging - $currentPage = 1; if (isset($_GET['paged'])) $currentPage = (int)sanitize_text_field($_GET['paged']); - - #} Sort - $sort = false; if (isset($_GET['sort']) && !empty($_GET['sort'])) $sort = sanitize_text_field($_GET['sort']); - $sortOrder = false; if (isset($_GET['sortdirection']) && ($_GET['sortdirection'] == 'asc' || $_GET['sortdirection'] == 'desc')) $sortOrder = sanitize_text_field($_GET['sortdirection']); + } + #} Paging + $currentPage = 1; + if ( isset( $_GET['paged'] ) ) { + $currentPage = (int) sanitize_text_field( $_GET['paged'] ); + } - # SCAFFOLDING - TO BE RE-ARRANGED :) - #} NOTE SECOND FIELD IN THESE ARE NOW IGNORED!?!? (30/7) + #} Sort + $sort = false; + if ( isset( $_GET['sort'] ) && ! empty( $_GET['sort'] ) ) { + $sort = sanitize_text_field( $_GET['sort'] ); + } + $sortOrder = false; + if ( isset( $_GET['sortdirection'] ) && ( $_GET['sortdirection'] == 'asc' || $_GET['sortdirection'] == 'desc' ) ) { + $sortOrder = sanitize_text_field( $_GET['sortdirection'] ); + } - #} Centralised into ZeroBSCRM.List.Columns.php 30/7/17 - $columnVar = 'zeroBSCRM_columns_'.$this->objType; //$zeroBSCRM_columns_transaction; - $defaultColumns = $GLOBALS[ $columnVar ]['default']; - $allColumns = $GLOBALS[ $columnVar ]['all']; + # SCAFFOLDING - TO BE RE-ARRANGED :) + #} NOTE SECOND FIELD IN THESE ARE NOW IGNORED!?!? (30/7) + #} Centralised into ZeroBSCRM.List.Columns.php 30/7/17 + $columnVar = 'zeroBSCRM_columns_' . $this->objType; // $zeroBSCRM_columns_transaction; + $defaultColumns = $GLOBALS[ $columnVar ]['default']; + $allColumns = $GLOBALS[ $columnVar ]['all']; - global $zbs; - $usingOwnership = $zbs->settings->get('perusercustomers'); + global $zbs; + $usingOwnership = $zbs->settings->get( 'perusercustomers' ); - #} Retrieve columns settings - $customViews = $zbs->settings->get('customviews2'); + #} Retrieve columns settings + $customViews = $zbs->settings->get( 'customviews2' ); - $currentColumns = false; if (isset($customViews) && isset($customViews[$this->objType])) $currentColumns = $customViews[$this->objType]; - if ($currentColumns == false) $currentColumns = $defaultColumns; + $currentColumns = false; + if ( isset( $customViews ) && isset( $customViews[ $this->objType ] ) ) { + $currentColumns = $customViews[ $this->objType ]; + } + if ( $currentColumns == false ) { + $currentColumns = $defaultColumns; + } // add all columns to sortables :) if ( is_array( $currentColumns ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -199,132 +210,145 @@ public function drawListView(){ $per_page = 20; } - #} Refresh 2 - ?> + #} Refresh 2 + ?> - + - +