diff --git a/projects/plugins/crm/.phan/baseline.php b/projects/plugins/crm/.phan/baseline.php index a4104157706b..b1d3ad87b0e3 100644 --- a/projects/plugins/crm/.phan/baseline.php +++ b/projects/plugins/crm/.phan/baseline.php @@ -9,15 +9,15 @@ */ return [ // # Issue statistics: - // PhanUndeclaredVariable : 870+ occurrences - // PhanTypeArraySuspiciousNullable : 420+ occurrences + // PhanUndeclaredVariable : 880+ occurrences + // PhanTypeArraySuspiciousNullable : 440+ occurrences // PhanRedundantCondition : 390+ occurrences // PhanTypeMismatchReturn : 300+ occurrences // PhanUnextractableAnnotationElementName : 200+ occurrences // PhanTypeArraySuspicious : 190+ occurrences + // PhanPossiblyUndeclaredVariable : 150+ occurrences // PhanTypeMismatchPropertyProbablyReal : 150+ occurrences // PhanPluginUnreachableCode : 140+ occurrences - // PhanPossiblyUndeclaredVariable : 140+ occurrences // PhanTypePossiblyInvalidDimOffset : 130+ occurrences // PhanTypeMismatchReturnProbablyReal : 110+ occurrences // PhanSuspiciousValueComparison : 100+ occurrences @@ -41,8 +41,8 @@ // PhanPluginDuplicateAdjacentStatement : 35+ occurrences // PhanPluginSimplifyExpressionBool : 35+ occurrences // PhanSuspiciousWeakTypeComparison : 30+ occurrences - // PhanUnreferencedUseNormal : 30+ occurrences // PhanParamSignatureMismatch : 25+ occurrences + // PhanUnreferencedUseNormal : 25+ occurrences // PhanCommentParamWithoutRealParam : 20+ occurrences // PhanParamSignaturePHPDocMismatchReturnType : 20+ occurrences // PhanPossiblyUndeclaredGlobalVariable : 20+ occurrences @@ -177,7 +177,7 @@ 'includes/ZeroBSCRM.DAL3.Obj.LineItems.php' => ['PhanEmptyForeach', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanSuspiciousWeakTypeComparison', 'PhanTypeArraySuspiciousNullable', 'PhanTypeComparisonFromArray', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchArgumentInternalReal', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchDefault', 'PhanTypeMismatchForeach', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnNullable', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredVariable', 'PhanUnextractableAnnotationElementName'], 'includes/ZeroBSCRM.DAL3.Obj.Logs.php' => ['PhanEmptyForeach', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginUnreachableCode', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanTypeArraySuspiciousNull', 'PhanTypeArraySuspiciousNullable', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchArgumentInternalReal', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchDefault', 'PhanTypeMismatchForeach', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredVariable', 'PhanUndeclaredVariableDim', 'PhanUnextractableAnnotationElementName'], 'includes/ZeroBSCRM.DAL3.Obj.QuoteTemplates.php' => ['PhanCommentParamWithoutRealParam', 'PhanEmptyForeach', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanSuspiciousWeakTypeComparison', 'PhanTypeArraySuspiciousNullable', 'PhanTypeComparisonFromArray', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchArgumentInternalReal', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchDefault', 'PhanTypeMismatchForeach', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnNullable', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredVariable', 'PhanUndeclaredVariableDim', 'PhanUnextractableAnnotationElementName'], - 'includes/ZeroBSCRM.DAL3.Obj.Quotes.php' => ['PhanCommentParamWithoutRealParam', 'PhanEmptyForeach', 'PhanNoopBinaryOperator', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanSuspiciousWeakTypeComparison', 'PhanTypeArraySuspiciousNull', 'PhanTypeArraySuspiciousNullable', 'PhanTypeComparisonFromArray', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentInternalReal', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentNullableInternal', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchDefault', 'PhanTypeMismatchDimFetchNullable', 'PhanTypeMismatchForeach', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnNullable', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredVariable', 'PhanUndeclaredVariableDim', 'PhanUnextractableAnnotationElementName'], + 'includes/ZeroBSCRM.DAL3.Obj.Quotes.php' => ['PhanCommentParamWithoutRealParam', 'PhanEmptyForeach', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanSuspiciousWeakTypeComparison', 'PhanTypeArraySuspiciousNull', 'PhanTypeArraySuspiciousNullable', 'PhanTypeComparisonFromArray', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentInternalReal', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentNullableInternal', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchDefault', 'PhanTypeMismatchDimFetchNullable', 'PhanTypeMismatchForeach', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnNullable', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredVariable', 'PhanUndeclaredVariableDim', 'PhanUnextractableAnnotationElementName'], 'includes/ZeroBSCRM.DAL3.Obj.Segments.php' => ['PhanEmptyForeach', 'PhanPluginNeverReturnMethod', 'PhanPluginUnreachableCode', 'PhanRedundantCondition', 'PhanTypeArraySuspiciousNullable', 'PhanTypeMismatchDefault', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredMethod', 'PhanUndeclaredVariable', 'PhanUnextractableAnnotationElementName'], 'includes/ZeroBSCRM.DAL3.Obj.Transactions.php' => ['PhanCommentParamWithoutRealParam', 'PhanEmptyForeach', 'PhanImpossibleTypeComparison', 'PhanNoopBinaryOperator', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanSuspiciousWeakTypeComparison', 'PhanTypeArraySuspicious', 'PhanTypeArraySuspiciousNull', 'PhanTypeArraySuspiciousNullable', 'PhanTypeComparisonFromArray', 'PhanTypeComparisonToArray', 'PhanTypeConversionFromArray', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentInternalReal', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentNullableInternal', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchDefault', 'PhanTypeMismatchDimFetchNullable', 'PhanTypeMismatchForeach', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnNullable', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredVariable', 'PhanUndeclaredVariableDim', 'PhanUnextractableAnnotationElementName'], 'includes/ZeroBSCRM.DAL3.ObjectLayer.php' => ['PhanCommentParamWithoutRealParam', 'PhanEmptyForeach', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanTypeArraySuspicious', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchArgumentInternalProbablyReal', 'PhanTypeMismatchDefault', 'PhanTypeMismatchForeach', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnNullable', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredFunction', 'PhanUnextractableAnnotationElementName'], @@ -192,13 +192,13 @@ 'includes/ZeroBSCRM.FormatHelpers.php' => ['PhanNoopVariable', 'PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanTypeArraySuspiciousNullable', 'PhanTypeInvalidLeftOperandOfAdd', 'PhanTypeMismatchArgument'], 'includes/ZeroBSCRM.Forms.php' => ['PhanPluginSimplifyExpressionBool', 'PhanTypeNonVarPassByRef'], 'includes/ZeroBSCRM.GeneralFuncs.php' => ['PhanCommentParamWithoutRealParam', 'PhanMisspelledAnnotation', 'PhanPluginNeverReturnFunction', 'PhanPluginSimplifyExpressionBool', 'PhanPluginUnreachableCode', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanTypeInvalidLeftOperandOfNumericOp', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchArgumentNullableInternal', 'PhanTypeMismatchDimFetch', 'PhanUndeclaredConstant', 'PhanUndeclaredFunction', 'PhanUndeclaredVariableDim'], - 'includes/ZeroBSCRM.IntegrationFuncs.php' => ['PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanRedundantCondition'], + 'includes/ZeroBSCRM.IntegrationFuncs.php' => ['PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanRedundantCondition', 'PhanTypeMismatchArgument'], 'includes/ZeroBSCRM.InternalAutomatorRecipes.php' => ['PhanPluginRedundantAssignment', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison'], 'includes/ZeroBSCRM.InvoiceBuilder.php' => ['PhanPluginDuplicateAdjacentStatement', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginDuplicateExpressionBinaryOp', 'PhanPluginRedundantAssignment', 'PhanPossiblyUndeclaredVariable', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchReturn', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredVariable'], 'includes/ZeroBSCRM.Jetpack.php' => ['PhanPluginDuplicateConditionalNullCoalescing'], 'includes/ZeroBSCRM.List.Columns.php' => ['PhanPluginMixedKeyNoKey'], 'includes/ZeroBSCRM.List.php' => ['PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanTypeArraySuspicious', 'PhanTypeArraySuspiciousNullable', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentInternal'], - 'includes/ZeroBSCRM.Mail.php' => ['PhanPluginMixedKeyNoKey', 'PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanUndeclaredClassCatch', 'PhanUndeclaredClassInstanceof', 'PhanUndeclaredClassMethod', 'PhanUndeclaredClassProperty', 'PhanUndeclaredClassReference', 'PhanUndeclaredVariable', 'PhanUnreferencedUseNormal'], + 'includes/ZeroBSCRM.Mail.php' => ['PhanPluginMixedKeyNoKey', 'PhanPluginRedundantAssignment', 'PhanPluginUnreachableCode', 'PhanRedundantCondition', 'PhanSuspiciousValueComparison', 'PhanUndeclaredClassCatch', 'PhanUndeclaredClassInstanceof', 'PhanUndeclaredClassMethod', 'PhanUndeclaredClassProperty', 'PhanUndeclaredClassReference', 'PhanUndeclaredVariable'], 'includes/ZeroBSCRM.MailTracking.php' => ['PhanTypeArraySuspiciousNullable'], 'includes/ZeroBSCRM.MetaBox.php' => ['PhanTypeConversionFromArray', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullableInternal'], 'includes/ZeroBSCRM.MetaBoxes3.Companies.php' => ['PhanDeprecatedFunction', 'PhanPluginDuplicateAdjacentStatement', 'PhanRedundantCondition', 'PhanTypeMismatchArgument', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredVariable'], @@ -222,7 +222,7 @@ 'includes/ZeroBSCRM.Social.php' => ['PhanMisspelledAnnotation', 'PhanTypeArraySuspiciousNullable'], 'includes/ZeroBSCRM.TagManager.php' => ['PhanEmptyForeach', 'PhanRedundantCondition', 'PhanUndeclaredProperty'], 'includes/class-learn-menu.php' => ['PhanPluginDuplicateExpressionBinaryOp', 'PhanRedundantCondition', 'PhanTypeInvalidDimOffset', 'PhanTypeMismatchDefault'], - 'includes/class-oauth-handler.php' => ['PhanTypeArraySuspicious', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredClassCatch', 'PhanUndeclaredClassMethod', 'PhanUndeclaredTypeReturnType', 'PhanUndeclaredVariable', 'PhanUnreferencedUseNormal'], + 'includes/class-oauth-handler.php' => ['PhanTypeArraySuspicious', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredClassCatch', 'PhanUndeclaredClassMethod', 'PhanUndeclaredTypeReturnType', 'PhanUndeclaredVariable'], 'includes/class-package-installer.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentNullableInternal', 'PhanUndeclaredClassMethod'], 'includes/jpcrm-dependency-checker.php' => ['PhanPossiblyUndeclaredVariable', 'PhanTypeMismatchArgumentNullable'], 'includes/jpcrm-fonts.php' => ['PhanUndeclaredClassMethod', 'PhanUndeclaredTypeParameter'], @@ -255,7 +255,7 @@ 'modules/woo-sync/admin/settings/connection_edit.page.php' => ['PhanPossiblyUndeclaredVariable', 'PhanTypeMismatchArgumentNullable'], 'modules/woo-sync/admin/settings/connections.page.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanPossiblyUndeclaredVariable'], 'modules/woo-sync/admin/woo-sync-hub/main.page.php' => ['PhanPossiblyUndeclaredVariable', 'PhanTypeMismatchArgumentNullable'], - 'modules/woo-sync/includes/class-woo-sync-background-sync-job.php' => ['PhanCommentParamWithoutRealParam', 'PhanPluginDuplicateCatchStatementBody', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanTypeArraySuspiciousNullable', 'PhanTypeComparisonFromArray', 'PhanTypeMagicVoidWithReturn', 'PhanTypeMismatchArgument', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredFunction', 'PhanUndeclaredMethod', 'PhanUndeclaredVariable', 'PhanUnextractableAnnotationElementName', 'PhanUnreferencedUseNormal'], + 'modules/woo-sync/includes/class-woo-sync-background-sync-job.php' => ['PhanCommentParamWithoutRealParam', 'PhanPluginDuplicateCatchStatementBody', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanPossiblyUndeclaredVariable', 'PhanRedundantCondition', 'PhanTypeArraySuspiciousNullable', 'PhanTypeComparisonFromArray', 'PhanTypeMagicVoidWithReturn', 'PhanTypeMismatchArgument', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredFunction', 'PhanUndeclaredMethod', 'PhanUndeclaredVariable', 'PhanUnextractableAnnotationElementName'], 'modules/woo-sync/includes/class-woo-sync-background-sync.php' => ['PhanUnextractableAnnotationElementName'], 'modules/woo-sync/includes/class-woo-sync-my-account-integration.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanRedundantCondition', 'PhanTypeArraySuspicious', 'PhanTypePossiblyInvalidDimOffset'], 'modules/woo-sync/includes/class-woo-sync-woo-admin-integration.php' => ['PhanUndeclaredClassMethod', 'PhanUndeclaredClassProperty', 'PhanUndeclaredTypeParameter'], diff --git a/projects/plugins/crm/.phpcs.dir.xml b/projects/plugins/crm/.phpcs.dir.xml index 59ce661e2543..806750a13bda 100644 --- a/projects/plugins/crm/.phpcs.dir.xml +++ b/projects/plugins/crm/.phpcs.dir.xml @@ -4,6 +4,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -30,7 +50,7 @@ - + diff --git a/projects/plugins/crm/admin/company/view.page.php b/projects/plugins/crm/admin/company/view.page.php index 3baf693e7afa..e42a9e378dd9 100644 --- a/projects/plugins/crm/admin/company/view.page.php +++ b/projects/plugins/crm/admin/company/view.page.php @@ -1,6 +1,5 @@ "; - 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/contact/view.page.php b/projects/plugins/crm/admin/contact/view.page.php index 48c4693f24b0..662bbc09fd75 100644 --- a/projects/plugins/crm/admin/contact/view.page.php +++ b/projects/plugins/crm/admin/contact/view.page.php @@ -1,6 +1,5 @@
' . esc_html__( 'View WordPress Profile', 'zero-bs-crm' ) . ''; + echo '

' . esc_html__( 'View WordPress Profile', 'zero-bs-crm' ) . ''; // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText -- "wordpress" is a Semantic UI icon class name, not the brand name. } ?> diff --git a/projects/plugins/crm/admin/crm-resources/main.page.php b/projects/plugins/crm/admin/crm-resources/main.page.php index 1c7268c0083e..b7a38dedc152 100644 --- a/projects/plugins/crm/admin/crm-resources/main.page.php +++ b/projects/plugins/crm/admin/crm-resources/main.page.php @@ -1,6 +1,5 @@ for a template variant selector setting (e.g. invoice pdf template) diff --git a/projects/plugins/crm/admin/settings/partials/title.block.php b/projects/plugins/crm/admin/settings/partials/title.block.php index f69e0fd53464..72269251a70a 100644 --- a/projects/plugins/crm/admin/settings/partials/title.block.php +++ b/projects/plugins/crm/admin/settings/partials/title.block.php @@ -1,6 +1,5 @@ ' . __( '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/admin/user-profile/main.page.php b/projects/plugins/crm/admin/user-profile/main.page.php index e267aeb2aaf0..5c1f46832cae 100644 --- a/projects/plugins/crm/admin/user-profile/main.page.php +++ b/projects/plugins/crm/admin/user-profile/main.page.php @@ -1,6 +1,5 @@ Reminders page */ defined( 'ZEROBSCRM_PATH' ) || exit( 0 ); diff --git a/projects/plugins/crm/admin/user-profile/user-profile.page.php b/projects/plugins/crm/admin/user-profile/user-profile.page.php index 374cb25bff3c..801142cbdde3 100644 --- a/projects/plugins/crm/admin/user-profile/user-profile.page.php +++ b/projects/plugins/crm/admin/user-profile/user-profile.page.php @@ -1,6 +1,5 @@ $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" => '', - '"' => '"', - "'" => ''', - "<" => '', + '"' => '"', + "'" => ''', + '<' => '', ) ); } @@ -4969,12 +4984,14 @@ function zeroBSCRM_AJAX_saveScreenOptions() { /* ====================================================== / Admin AJAX: Screen options DAL2 -====================================================== */ +====================================================== +*/ /* ====================================================== Admin AJAX: Inline Editor -====================================================== */ +====================================================== +*/ // } Save any inline-edits add_action( 'wp_ajax_zbs_list_save_inline_edit', 'zeroBSCRM_AJAX_listViewInlineEdit_save' ); @@ -5029,7 +5046,8 @@ function zeroBSCRM_AJAX_listViewInlineEdit_save() { /* ====================================================== / Admin AJAX: Inline Editor -====================================================== */ +====================================================== +*/ /* ====================================================== @@ -5601,7 +5619,8 @@ function zeroBSCRM_AJAX_getInvoice() { /* ====================================================== Admin AJAX: Tasks -====================================================== */ +====================================================== +*/ add_action( 'wp_ajax_mark_task_complete', 'zeroBSCRM_ajax_mark_task_complete' ); function zeroBSCRM_ajax_mark_task_complete() { @@ -5636,5 +5655,5 @@ function zeroBSCRM_ajax_mark_task_complete() { /* ====================================================== / Admin AJAX: Tasks -====================================================== */ - +====================================================== +*/ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.API.php b/projects/plugins/crm/includes/ZeroBSCRM.API.php index 50a896adf4fa..16ed81e54d7a 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.API.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.API.php @@ -1,6 +1,5 @@ zbsmail_active ) { // 1 = active, 0 = inactive.. echo '
- -
- -
'; + position: absolute; + top: 19px; + right: 20px;"> + +
+ + '; } else { echo '
- -
- -
'; + position: absolute; + top: 19px; + right: 20px;"> + +
+ + '; } } @@ -2081,8 +2080,8 @@ function zeroBSCRM_html_extensions() { usort( $top_woo_extensions, function ( - $str1, - $str2 + $str1, + $str2 ) { return strcasecmp( $str1->name, $str2->name ); } @@ -2092,8 +2091,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..34e7698b75e0 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.AdminStyling.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.AdminStyling.php @@ -1,6 +1,5 @@ base == 'dashboard' ) { diff --git a/projects/plugins/crm/includes/ZeroBSCRM.CRON.php b/projects/plugins/crm/includes/ZeroBSCRM.CRON.php index 28c9c95bfd0d..7245a74517cd 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.CRON.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.CRON.php @@ -1,6 +1,5 @@ slugs['csvlite'], 'zeroBSCRM_CSVImporterLitepages_app', 1 ); // phpcs:ignore WordPress.WP.Capabilities.Unknown @@ -289,7 +288,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.Extensions.php b/projects/plugins/crm/includes/ZeroBSCRM.Core.Extensions.php index 227266b14b86..96647afd025a 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Core.Extensions.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Core.Extensions.php @@ -1,6 +1,5 @@ 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..0a83046ab1cb 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.CustomerFilters.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.CustomerFilters.php @@ -1,6 +1,5 @@ var zbscrmBHURLCompanies = "' . $rest_url . '";'; - $haszbscrmBHURLCompaniesOut = true; + $haszbscrmBHURLCompaniesOut = true; } // } Global JS does the rest ;) @@ -410,7 +409,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.DAL.Fields.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL.Fields.php index 8918659eaead..d7f6e15cb945 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL.Fields.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL.Fields.php @@ -1,6 +1,5 @@ array( @@ -108,12 +108,14 @@ function zeroBSCRM_fields_initialise() { /* ====================================================== / Legacy / Unchanged - ====================================================== */ + ====================================================== + */ /* ====================================================== Contacts - ====================================================== */ + ====================================================== + */ // Load from object model :) $zbsCustomerFields = $zbs->DAL->contacts->generateFieldsGlobalArr(); @@ -149,12 +151,14 @@ function zeroBSCRM_fields_initialise() { /* ====================================================== / Contacts - ====================================================== */ + ====================================================== + */ /* ====================================================== Companies - ====================================================== */ + ====================================================== + */ // Load from object model :) $zbsCompanyFields = $zbs->DAL->companies->generateFieldsGlobalArr(); @@ -188,12 +192,14 @@ function zeroBSCRM_fields_initialise() { /* ====================================================== / Companies - ====================================================== */ + ====================================================== + */ /* ====================================================== Quotes - ====================================================== */ + ====================================================== + */ // Load from object model :) $zbsCustomerQuoteFields = $zbs->DAL->quotes->generateFieldsGlobalArr(); @@ -215,12 +221,14 @@ function zeroBSCRM_fields_initialise() { /* ====================================================== / Quotes - ====================================================== */ + ====================================================== + */ /* ====================================================== Invoices - ====================================================== */ + ====================================================== + */ /* NOTE: @@ -258,12 +266,14 @@ function zeroBSCRM_fields_initialise() { /* ====================================================== / Invoices - ====================================================== */ + ====================================================== + */ /* ====================================================== Transactions - ====================================================== */ + ====================================================== + */ // Load from object model :) $zbsTransactionFields = $zbs->DAL->transactions->generateFieldsGlobalArr(); @@ -284,12 +294,14 @@ function zeroBSCRM_fields_initialise() { /* ====================================================== / Transactions - ====================================================== */ + ====================================================== + */ /* ====================================================== Forms - ====================================================== */ + ====================================================== + */ // Load from object model :) $zbsFormFields = $zbs->DAL->forms->generateFieldsGlobalArr(); @@ -316,7 +328,8 @@ function zeroBSCRM_fields_initialise() { /* ====================================================== / Forms - ====================================================== */ + ====================================================== + */ } /* @@ -397,7 +410,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 +1302,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 +1345,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.Helpers.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Helpers.php index 7fecba18a2eb..5bf3593c0784 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Helpers.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Helpers.php @@ -1,5 +1,5 @@ 3 (Mostly customer/contact + log relatead) - ====================================================== */ +/* +====================================================== + Unchanged DAL2->3 (Mostly customer/contact + log relatead) +====================================================== */ -function zeroBS_getCustomer($cID=-1,$withInvoices=false,$withQuotes=false,$withTransactions=false){ +function zeroBS_getCustomer( $cID = -1, $withInvoices = false, $withQuotes = false, $withTransactions = false ) { - global $zbs; return $zbs->DAL->contacts->getContact($cID,array( + global $zbs; + return $zbs->DAL->contacts->getContact( + $cID, + array( // with what? - 'withCustomFields' => true, - 'withQuotes' => $withQuotes, - 'withInvoices' => $withInvoices, - 'withTransactions' => $withTransactions, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) - - )); + 'withCustomFields' => true, + 'withQuotes' => $withQuotes, + 'withInvoices' => $withInvoices, + 'withTransactions' => $withTransactions, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } -function zeroBS_getCustomerName($contactID=-1){ - - global $zbs; return $zbs->DAL->contacts->getContactFullNameEtc($contactID,array(),array( - 'incFirstLineAddr' => true, - 'incID' => true - )); +function zeroBS_getCustomerName( $contactID = -1 ) { + global $zbs; + return $zbs->DAL->contacts->getContactFullNameEtc( + $contactID, + array(), + array( + 'incFirstLineAddr' => true, + 'incID' => true, + ) + ); } -function zeroBS_customerName($contactID='',$contactArr=false,$incFirstLineAddr=true,$incID=true){ - - global $zbs; return $zbs->DAL->contacts->getContactFullNameEtc($contactID,$contactArr,array( - 'incFirstLineAddr' => $incFirstLineAddr, - 'incID' => $incID - )); - - +function zeroBS_customerName( $contactID = '', $contactArr = false, $incFirstLineAddr = true, $incID = true ) { + + global $zbs; + return $zbs->DAL->contacts->getContactFullNameEtc( + $contactID, + $contactArr, + array( + 'incFirstLineAddr' => $incFirstLineAddr, + 'incID' => $incID, + ) + ); } -function zeroBS_getCustomerNameShort($contactID=-1){ +function zeroBS_getCustomerNameShort( $contactID = -1 ) { - global $zbs; return $zbs->DAL->contacts->getContactFullNameEtc($contactID,array(),array( - 'incFirstLineAddr' => false, - 'incID' => false - )); + global $zbs; + return $zbs->DAL->contacts->getContactFullNameEtc( + $contactID, + array(), + array( + 'incFirstLineAddr' => false, + 'incID' => false, + ) + ); } -function zeroBS_customerAddr($contactID='',$contactArr=array(),$addrFormat = 'short',$delimiter= ', '){ - - global $zbs; return $zbs->DAL->contacts->getContactAddress($contactID,array(),array( - 'addrFormat' => $addrFormat, - 'delimiter' => $delimiter - )); +function zeroBS_customerAddr( $contactID = '', $contactArr = array(), $addrFormat = 'short', $delimiter = ', ' ) { + global $zbs; + return $zbs->DAL->contacts->getContactAddress( + $contactID, + array(), + array( + 'addrFormat' => $addrFormat, + 'delimiter' => $delimiter, + ) + ); } #} Returns a str of address, ($third param = 'short','full') #} Pass an ID OR a customerMeta array (saves loading ;) - in fact doesn't even work with ID yet... lol) -function zeroBS_customerSecondAddr($contactID='',$contactArr=array(),$addrFormat = 'short',$delimiter= ', '){ - - global $zbs; return $zbs->DAL->contacts->getContact2ndAddress($contactID,array(),array( - 'addrFormat' => $addrFormat, - 'delimiter' => $delimiter - )); +function zeroBS_customerSecondAddr( $contactID = '', $contactArr = array(), $addrFormat = 'short', $delimiter = ', ' ) { + global $zbs; + return $zbs->DAL->contacts->getContact2ndAddress( + $contactID, + array(), + array( + 'addrFormat' => $addrFormat, + 'delimiter' => $delimiter, + ) + ); } -function zeroBS_customerEmail($contactID='',$contactArr=false){ - - global $zbs; return $zbs->DAL->contacts->getContactEmail($contactID); +function zeroBS_customerEmail( $contactID = '', $contactArr = false ) { + global $zbs; + return $zbs->DAL->contacts->getContactEmail( $contactID ); } -function zeroBS_customerMobile($contactID='',$contactArr=false){ - - global $zbs; return $zbs->DAL->contacts->getContactMobile($contactID); +function zeroBS_customerMobile( $contactID = '', $contactArr = false ) { + global $zbs; + return $zbs->DAL->contacts->getContactMobile( $contactID ); } -function zeroBS_customerAvatarHTML($contactID='',$contactArr=false,$size=100,$extraClasses=''){ - - global $zbs; return $zbs->DAL->contacts->getContactAvatarHTML($contactID,$size,$extraClasses); +function zeroBS_customerAvatarHTML( $contactID = '', $contactArr = false, $size = 100, $extraClasses = '' ) { + global $zbs; + return $zbs->DAL->contacts->getContactAvatarHTML( $contactID, $size, $extraClasses ); } -function zeroBS_customerCount(){ - - global $zbs; return $zbs->DAL->contacts->getContactCount(array('ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); +function zeroBS_customerCount() { + global $zbs; + return $zbs->DAL->contacts->getContactCount( array( 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) ) ); } #} Retrieves company post id if associated with customer // note 2.5+ can have multiple co's, but this'll only return first ID, need to move away from this -function zeroBS_getCustomerCompanyID($cID=-1){ +function zeroBS_getCustomerCompanyID( $cID = -1 ) { - global $zbs; $coArr = $zbs->DAL->contacts->getContactCompanies($cID); - if (is_array($coArr) && count($coArr) > 0) return $coArr[0]['id']; + global $zbs; + $coArr = $zbs->DAL->contacts->getContactCompanies( $cID ); + if ( is_array( $coArr ) && count( $coArr ) > 0 ) { + return $coArr[0]['id']; + } return false; } #} sets company id associated with customer (note this'll override any existing val) // note 2.5+ can have multiple co's, but this'll only add first ID, need to move away from this -function zeroBS_setCustomerCompanyID($cID=-1,$coID=-1){ +function zeroBS_setCustomerCompanyID( $cID = -1, $coID = -1 ) { global $zbs; - if (!empty($cID) && !empty($coID)) { - - return $zbs->DAL->contacts->addUpdateContactCompanies(array( - 'id' => $cID, - 'companyIDs' => array($coID))); - + if ( ! empty( $cID ) && ! empty( $coID ) ) { + + return $zbs->DAL->contacts->addUpdateContactCompanies( + array( + 'id' => $cID, + 'companyIDs' => array( $coID ), + ) + ); + } return false; } -function zbsCRM_addUpdateCustomerCompany($customerID=-1,$companyID=-1){ +function zbsCRM_addUpdateCustomerCompany( $customerID = -1, $companyID = -1 ) { global $zbs; - if (!empty($customerID) && !empty($companyID)) { - - return $zbs->DAL->contacts->addUpdateContactCompanies(array( - 'id' => $customerID, - 'companyIDs' => array($companyID))); - + if ( ! empty( $customerID ) && ! empty( $companyID ) ) { + + return $zbs->DAL->contacts->addUpdateContactCompanies( + array( + 'id' => $customerID, + 'companyIDs' => array( $companyID ), + ) + ); + } return false; - } #} Retrieves wp id for a customer -function zeroBS_getCustomerWPID($cID=-1){ - - global $zbs; return $zbs->DAL->contacts->getContactWPID($cID); +function zeroBS_getCustomerWPID( $cID = -1 ) { + global $zbs; + return $zbs->DAL->contacts->getContactWPID( $cID ); } #} Retrieves wp id for a customer -function zeroBS_getCustomerIDFromWPID($wpID=-1){ - - global $zbs; return $zbs->DAL->contacts->getContact(-1,array( - 'WPID'=>$wpID, - 'onlyID'=>1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); +function zeroBS_getCustomerIDFromWPID( $wpID = -1 ) { + global $zbs; + return $zbs->DAL->contacts->getContact( + -1, + array( + 'WPID' => $wpID, + 'onlyID' => 1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } #} Sets a WP id against a customer -function zeroBS_setCustomerWPID($cID=-1,$wpID=-1){ - - global $zbs; return $zbs->DAL->contacts->addUpdateContactWPID(array('id'=>$cID,'WPID'=>$wpID)); +function zeroBS_setCustomerWPID( $cID = -1, $wpID = -1 ) { + global $zbs; + return $zbs->DAL->contacts->addUpdateContactWPID( + array( + 'id' => $cID, + 'WPID' => $wpID, + ) + ); } -function zeroBSCRM_getCustomerTags($hide_empty=false){ - - global $zbs; - - return $zbs->DAL->getTagsForObjType(array( - 'objtypeid'=>ZBS_TYPE_CONTACT, - 'excludeEmpty'=>$hide_empty, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - +function zeroBSCRM_getCustomerTags( $hide_empty = false ) { + + global $zbs; + + return $zbs->DAL->getTagsForObjType( + array( + 'objtypeid' => ZBS_TYPE_CONTACT, + 'excludeEmpty' => $hide_empty, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } -// either or -function zeroBSCRM_setContactTags($cID=-1,$tags=array(),$tagIDs=array(),$mode='replace'){ +// either or +function zeroBSCRM_setContactTags( $cID = -1, $tags = array(), $tagIDs = array(), $mode = 'replace' ) { - if ($cID > 0){ + if ( $cID > 0 ) { $args = array( - 'id' => $cID, - 'mode' => $mode - ); + 'id' => $cID, + 'mode' => $mode, + ); // got tags? if ( is_array( $tags ) && ! empty( $tags ) ) { @@ -223,71 +261,74 @@ function zeroBSCRM_setContactTags($cID=-1,$tags=array(),$tagIDs=array(),$mode='r global $zbs; - return $zbs->DAL->contacts->addUpdateContactTags($args); + return $zbs->DAL->contacts->addUpdateContactTags( $args ); } return false; - } -function zeroBSCRM_getContactTagsArr($hide_empty=true){ - - global $zbs; - - return $zbs->DAL->getTagsForObjType(array( - 'objtypeid'=>ZBS_TYPE_CONTACT, - 'excludeEmpty'=>$hide_empty, - 'withCount' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - +function zeroBSCRM_getContactTagsArr( $hide_empty = true ) { + + global $zbs; + + return $zbs->DAL->getTagsForObjType( + array( + 'objtypeid' => ZBS_TYPE_CONTACT, + 'excludeEmpty' => $hide_empty, + 'withCount' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } -function zeroBS_getCustomerIcoHTML($cID=-1,$additionalClasses=''){ +function zeroBS_getCustomerIcoHTML( $cID = -1, $additionalClasses = '' ) { $thumbHTML = ''; - global $zbs; $thumbURL = $zbs->DAL->contacts->getContactAvatarURL($cID); - if (!empty($thumbURL)) { + global $zbs; + $thumbURL = $zbs->DAL->contacts->getContactAvatarURL( $cID ); + if ( ! empty( $thumbURL ) ) { $thumbHTML = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - return '
'.$thumbHTML.'
'; + return '
' . $thumbHTML . '
'; } - -function zeroBS_getCustomerIDWithEmail($custEmail=''){ +function zeroBS_getCustomerIDWithEmail( $custEmail = '' ) { /** * @var $custEmail the customer email you want to check if a contact exists for - * + * * @return returns return $potentialRes->ID from $zbs->DAL->contacts->getContact().. - * */ - global $zbs; - return $zbs->DAL->contacts->getContact(-1,array( - 'email'=>$custEmail, - 'onlyID'=>true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - + global $zbs; + return $zbs->DAL->contacts->getContact( + -1, + array( + 'email' => $custEmail, + 'onlyID' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } - -function zeroBS_searchCustomers($args=array(),$withMoneyData=false){ +function zeroBS_searchCustomers( $args = array(), $withMoneyData = false ) { // here I've shoehorned old into new, - // NOTE: + // NOTE: // this WONT return same exact fields - $args['ignoreowner'] = zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT); + $args['ignoreowner'] = zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ); - if ($withMoneyData){ + if ( $withMoneyData ) { - $args['withInvoices'] = true; + $args['withInvoices'] = true; $args['withTransactions'] = true; } - global $zbs; return $zbs->DAL->contacts->getContacts($args); + global $zbs; + return $zbs->DAL->contacts->getContacts( $args ); } /** @@ -318,26 +359,25 @@ function zeroBSCRM_customerPortalDisableEnable( $contact_id = -1, $enable_or_dis return false; } - /* * Resets the password for client portal access for a contact, by ID */ -function zeroBSCRM_customerPortalPWReset( $contact_id=-1 ) { +function zeroBSCRM_customerPortalPWReset( $contact_id = -1 ) { global $zbs; - if ( zeroBSCRM_permsCustomers() && !empty( $contact_id ) ) { - - $wp_user_id = zeroBS_getCustomerWPID( $contact_id ); - $contact = $zbs->DAL->contacts->getContact( $contact_id ); + if ( zeroBSCRM_permsCustomers() && ! empty( $contact_id ) ) { + + $wp_user_id = zeroBS_getCustomerWPID( $contact_id ); + $contact = $zbs->DAL->contacts->getContact( $contact_id ); $contact_email = $contact['email']; - $user_object = get_userdata( $contact_email ); + $user_object = get_userdata( $contact_email ); - if ( $wp_user_id > 0 && !empty( $contact_email ) ) { + if ( $wp_user_id > 0 && ! empty( $contact_email ) ) { // Verify this user can be changed // (Has to have singular role of `zerobs_customer`. This helps to avoid users resetting each others passwords via crm) - if ( jpcrm_role_check( $user_object, array(), array(), array( 'zerobs_customer' ) ) ) { + if ( jpcrm_role_check( $user_object, array(), array(), array( 'zerobs_customer' ) ) ) { return false; @@ -368,14 +408,14 @@ function zeroBSCRM_customerPortalPWReset( $contact_id=-1 ) { $mailArray = array( 'toEmail' => $contact_email, 'toName' => '', - 'subject' => zeroBSCRM_mailTemplate_getSubject(ZBSEMAIL_CLIENTPORTALPWREST), - 'headers' => zeroBSCRM_mailTemplate_getHeaders(ZBSEMAIL_CLIENTPORTALPWREST), + 'subject' => zeroBSCRM_mailTemplate_getSubject( ZBSEMAIL_CLIENTPORTALPWREST ), + 'headers' => zeroBSCRM_mailTemplate_getHeaders( ZBSEMAIL_CLIENTPORTALPWREST ), 'body' => $emailHTML, 'textbody' => '', 'options' => array( - 'html' => 1 + 'html' => 1, ), - 'tracking' => array( + 'tracking' => array( // tracking :D (auto-inserted pixel + saved in history db) 'emailTypeID' => ZBSEMAIL_CLIENTPORTALPWREST, 'targetObjID' => $contact_id, @@ -388,19 +428,19 @@ function zeroBSCRM_customerPortalPWReset( $contact_id=-1 ) { // and logs trcking :) // discern del method - $mailDeliveryMethod = zeroBSCRM_mailTemplate_getMailDelMethod(ZBSEMAIL_CLIENTPORTALPWREST); - if (!isset($mailDeliveryMethod) || empty($mailDeliveryMethod)) $mailDeliveryMethod = -1; + $mailDeliveryMethod = zeroBSCRM_mailTemplate_getMailDelMethod( ZBSEMAIL_CLIENTPORTALPWREST ); + if ( ! isset( $mailDeliveryMethod ) || empty( $mailDeliveryMethod ) ) { + $mailDeliveryMethod = -1; + } // send - $sent = zeroBSCRM_mailDelivery_sendMessage($mailDeliveryMethod,$mailArray); - + $sent = zeroBSCRM_mailDelivery_sendMessage( $mailDeliveryMethod, $mailArray ); // =================================== / MAIL SENDING ======================================= // ========================================================================================== } - return $new_password; } // if wpid @@ -408,14 +448,13 @@ function zeroBSCRM_customerPortalPWReset( $contact_id=-1 ) { } return false; - } // Returns bool of whether or not a specific customer can access client portal -function zeroBSCRM_isCustomerPortalDisabled( $contact_id=-1 ) { +function zeroBSCRM_isCustomerPortalDisabled( $contact_id = -1 ) { // No Contact ID, no entry, unless Admin or Jetpack CRM Admin we can let those in. - $contact_id = (int)$contact_id; + $contact_id = (int) $contact_id; if ( $contact_id < 1 ) { if ( zeroBSCRM_isZBSAdminOrAdmin() ) { return false; @@ -431,96 +470,110 @@ function zeroBSCRM_isCustomerPortalDisabled( $contact_id=-1 ) { // default = closed door return true; - } // loads customer record + creates a portal user for record // replaces zeroBSCRM_genPortalUser -function zeroBSCRM_createClientPortalUserFromRecord($cID=-1){ +function zeroBSCRM_createClientPortalUserFromRecord( $cID = -1 ) { - if (!empty($cID)){ + if ( ! empty( $cID ) ) { global $zbs; - // existing? - $existing = zeroBSCRM_getClientPortalUserID($cID); - if (!empty($existing) || $existing > 0) return false; + // existing? + $existing = zeroBSCRM_getClientPortalUserID( $cID ); + if ( ! empty( $existing ) || $existing > 0 ) { + return false; + } - $email = $zbs->DAL->contacts->getContactEmail($cID); - $contact = $zbs->DAL->contacts->getContact($cID,array('fields'=>array('zbsc_fname','zbsc_lname'))); - $fname = ''; if (isset($contact['fname']) && !empty($contact['fname'])) $fname = $contact['fname']; - $lname = ''; if (isset($contact['lname']) && !empty($contact['lname'])) $lname = $contact['lname']; + $email = $zbs->DAL->contacts->getContactEmail( $cID ); + $contact = $zbs->DAL->contacts->getContact( $cID, array( 'fields' => array( 'zbsc_fname', 'zbsc_lname' ) ) ); + $fname = ''; + if ( isset( $contact['fname'] ) && ! empty( $contact['fname'] ) ) { + $fname = $contact['fname']; + } + $lname = ''; + if ( isset( $contact['lname'] ) && ! empty( $contact['lname'] ) ) { + $lname = $contact['lname']; + } // fire - return zeroBSCRM_createClientPortalUser($cID,$email,12,$fname,$lname); + return zeroBSCRM_createClientPortalUser( $cID, $email, 12, $fname, $lname ); - } + } return false; - } -function zeroBSCRM_getClientPortalUserID($cID=-1){ +function zeroBSCRM_getClientPortalUserID( $cID = -1 ) { - if (!empty($cID)){ + if ( ! empty( $cID ) ) { - global $zbs; + global $zbs; - //first lets check if a user already exists with that email.. - $email = $zbs->DAL->contacts->getContactEmail($cID); - if (!empty($email)){ - $userID = email_exists($email); - if($userID != null){ - //update_post_meta($cID, 'zbs_portal_wpid', $userID); - $zbs->DAL->contacts->addUpdateContactWPID(array('id'=>$cID,'WPID'=>$userID)); - } - }else{ - //no email in meta, but might be linked? - //$userID = get_post_meta($cID, 'zbs_portal_wpid', true); - $userID = $zbs->DAL->contacts->getContactWPID($cID); + // first lets check if a user already exists with that email.. + $email = $zbs->DAL->contacts->getContactEmail( $cID ); + if ( ! empty( $email ) ) { + $userID = email_exists( $email ); + if ( $userID != null ) { + // update_post_meta($cID, 'zbs_portal_wpid', $userID); + $zbs->DAL->contacts->addUpdateContactWPID( + array( + 'id' => $cID, + 'WPID' => $userID, + ) + ); } - return $userID; - } - return false; + } else { + // no email in meta, but might be linked? + // $userID = get_post_meta($cID, 'zbs_portal_wpid', true); + $userID = $zbs->DAL->contacts->getContactWPID( $cID ); + } + return $userID; + } + return false; } -function zeroBSCRM_getClientPortalUserWPObj($cID=-1){ - - if (!empty($cID)){ +function zeroBSCRM_getClientPortalUserWPObj( $cID = -1 ) { - global $zbs; + if ( ! empty( $cID ) ) { - //$user_id = zeroBSCRM_getClientPortalUserID($cID); - $user_id = $zbs->DAL->contacts->getContactWPID($cID); + global $zbs; - return new WP_User( $user_id ); + // $user_id = zeroBSCRM_getClientPortalUserID($cID); + $user_id = $zbs->DAL->contacts->getContactWPID( $cID ); - } + return new WP_User( $user_id ); - return false; + } + return false; } // Function to update the zbs<->wp user link -function zeroBSCRM_setClientPortalUser($cID=-1,$wpUserID=-1){ +function zeroBSCRM_setClientPortalUser( $cID = -1, $wpUserID = -1 ) { - if ($cID > 0 && $wpUserID > 0){ + if ( $cID > 0 && $wpUserID > 0 ) { global $zbs; - $zbs->DAL->contacts->addUpdateContactWPID(array('id'=>$cID,'WPID'=>$wpUserID)); - + $zbs->DAL->contacts->addUpdateContactWPID( + array( + 'id' => $cID, + 'WPID' => $wpUserID, + ) + ); + return true; } return false; - } -function zeroBSCRM_createClientPortalUser( $cID=-1, $email='', $passwordLength=12, $first_name='', $last_name='' ) { +function zeroBSCRM_createClientPortalUser( $cID = -1, $email = '', $passwordLength = 12, $first_name = '', $last_name = '' ) { // fail if bad params - if ( empty( $cID ) || empty( $email ) || !zeroBSCRM_validateEmail( $email ) ) { + if ( empty( $cID ) || empty( $email ) || ! zeroBSCRM_validateEmail( $email ) ) { return false; } @@ -535,12 +588,12 @@ function zeroBSCRM_createClientPortalUser( $cID=-1, $email='', $passwordLength=1 // organise WP user details $wpUserDeets = array( - 'user_email' => $email, - 'user_login' => $email, - 'user_pass' => $password, - 'nickname' => $email, - 'first_name' => empty( $first_name ) ? '' : $first_name, - 'last_name' => empty( $last_name ) ? '' : $last_name, + 'user_email' => $email, + 'user_login' => $email, + 'user_pass' => $password, + 'nickname' => $email, + 'first_name' => empty( $first_name ) ? '' : $first_name, + 'last_name' => empty( $last_name ) ? '' : $last_name, ); // create WP user @@ -550,12 +603,17 @@ function zeroBSCRM_createClientPortalUser( $cID=-1, $email='', $passwordLength=1 $user = new WP_User( $user_id ); // fail if the user doesn't exist - if ( !$user->exists() ) { + if ( ! $user->exists() ) { return false; } // link WP user ID to contact - $zbs->DAL->contacts->addUpdateContactWPID( array( 'id' => $cID, 'WPID' => $user_id ) ); + $zbs->DAL->contacts->addUpdateContactWPID( + array( + 'id' => $cID, + 'WPID' => $user_id, + ) + ); // any extra assigned role? (from settings) $extraRole = zeroBSCRM_getSetting( 'portalusers_extrarole' ); @@ -570,30 +628,30 @@ function zeroBSCRM_createClientPortalUser( $cID=-1, $email='', $passwordLength=1 } // check if the email template is active, and if it is, send... - $active = zeroBSCRM_get_email_status(ZBSEMAIL_CLIENTPORTALWELCOME); - if ( $active ){ + $active = zeroBSCRM_get_email_status( ZBSEMAIL_CLIENTPORTALWELCOME ); + if ( $active ) { // generate html $emailHTML = zeroBSCRM_Portal_generateNotificationHTML( $password, true, $email, $cID ); // build send array $mailArray = array( - 'toEmail' => $email, - 'toName' => '', - 'subject' => zeroBSCRM_mailTemplate_getSubject( ZBSEMAIL_CLIENTPORTALWELCOME ), - 'headers' => zeroBSCRM_mailTemplate_getHeaders( ZBSEMAIL_CLIENTPORTALWELCOME ), - 'body' => $emailHTML, - 'textbody' => '', - 'options' => array( - 'html' => 1 + 'toEmail' => $email, + 'toName' => '', + 'subject' => zeroBSCRM_mailTemplate_getSubject( ZBSEMAIL_CLIENTPORTALWELCOME ), + 'headers' => zeroBSCRM_mailTemplate_getHeaders( ZBSEMAIL_CLIENTPORTALWELCOME ), + 'body' => $emailHTML, + 'textbody' => '', + 'options' => array( + 'html' => 1, ), - 'tracking' => array( + 'tracking' => array( // tracking :D (auto-inserted pixel + saved in history db) 'emailTypeID' => ZBSEMAIL_CLIENTPORTALWELCOME, 'targetObjID' => $cID, 'senderWPID' => -10, - 'associatedObjID' => -1 // none - ) + 'associatedObjID' => -1, // none + ), ); // Sends email, including tracking, via setting stored route out, (or default if none) @@ -601,7 +659,7 @@ function zeroBSCRM_createClientPortalUser( $cID=-1, $email='', $passwordLength=1 // discern del method $mailDeliveryMethod = zeroBSCRM_mailTemplate_getMailDelMethod( ZBSEMAIL_CLIENTPORTALWELCOME ); - if ( !isset( $mailDeliveryMethod ) || empty( $mailDeliveryMethod ) ) { + if ( ! isset( $mailDeliveryMethod ) || empty( $mailDeliveryMethod ) ) { $mailDeliveryMethod = -1; } @@ -619,28 +677,26 @@ function zeroBSCRM_createClientPortalUser( $cID=-1, $email='', $passwordLength=1 'userEmail' => $email, ) ); - } - - // THIS IS NOW DEPRECATED db2+ // (META used to be all deets, it's now normal deets - as table) #} Quick wrapper to future-proof. #} Should later replace all get_post_meta's with this -function zeroBS_getCustomerMeta($cID=-1){ +function zeroBS_getCustomerMeta( $cID = -1 ) { global $zbs; - //if (!empty($cID)) return get_post_meta($cID, 'zbs_customer_meta', true); + // if (!empty($cID)) return get_post_meta($cID, 'zbs_customer_meta', true); // Return contact directly DB2+ - if (!empty($cID)) return $zbs->DAL->contacts->getContact($cID,array('ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + if ( ! empty( $cID ) ) { + return $zbs->DAL->contacts->getContact( $cID, array( 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) ) ); + } return false; - } // generates a 'demo' customer object (excluding custom fields) -function zeroBS_getDemoCustomer(){ +function zeroBS_getDemoCustomer() { global $zbs, $zbsCustomerFields; @@ -649,30 +705,30 @@ function zeroBS_getDemoCustomer(){ $demoData = array( 'status' => array( 'Lead', 'Customer' ), - 'prefix' => array('Mr', 'Mrs', 'Miss'), - 'fname' => array('John','Jim','Mike','Melvin','Janet','Jennifer','Judy','Julie'), - 'lname' => array('Smith','Jones','Scott','Filbert'), - 'fullname' => array('John Smith','Jim Ellison','Mike Myers','Melvin Malcolms'), - 'addr1' => array('101 Red Street','26 Somerset Street','1 London Road'), - 'addr2' => array('Winchester','Leeds Village','Webleck'), - 'city' => array('London','Los Angeles','Leeds','Exeter'), - 'county' => array('London','Hertfordshire','California','Montana'), - 'postcode' => array('A1 1XU','AO12 3RR','E1 3XG','M1 3LF'), - 'secaddr_addr1' => array('101 Red Street','26 Somerset Street','1 London Road'), - 'secaddr_addr2' => array('Winchester','Leeds Village','Webleck'), - 'secaddr_city' => array('London','Los Angeles','Leeds','Exeter'), - 'secaddr_county' => array('London','Hertfordshire','California','Buckinghamshire'), - 'secaddr_postcode' => array('A1 1XU','AO12 3RR','E1 3XG','M1 3LF'), + 'prefix' => array( 'Mr', 'Mrs', 'Miss' ), + 'fname' => array( 'John', 'Jim', 'Mike', 'Melvin', 'Janet', 'Jennifer', 'Judy', 'Julie' ), + 'lname' => array( 'Smith', 'Jones', 'Scott', 'Filbert' ), + 'fullname' => array( 'John Smith', 'Jim Ellison', 'Mike Myers', 'Melvin Malcolms' ), + 'addr1' => array( '101 Red Street', '26 Somerset Street', '1 London Road' ), + 'addr2' => array( 'Winchester', 'Leeds Village', 'Webleck' ), + 'city' => array( 'London', 'Los Angeles', 'Leeds', 'Exeter' ), + 'county' => array( 'London', 'Hertfordshire', 'California', 'Montana' ), + 'postcode' => array( 'A1 1XU', 'AO12 3RR', 'E1 3XG', 'M1 3LF' ), + 'secaddr_addr1' => array( '101 Red Street', '26 Somerset Street', '1 London Road' ), + 'secaddr_addr2' => array( 'Winchester', 'Leeds Village', 'Webleck' ), + 'secaddr_city' => array( 'London', 'Los Angeles', 'Leeds', 'Exeter' ), + 'secaddr_county' => array( 'London', 'Hertfordshire', 'California', 'Buckinghamshire' ), + 'secaddr_postcode' => array( 'A1 1XU', 'AO12 3RR', 'E1 3XG', 'M1 3LF' ), // dirty repetition... - 'secaddr1' => array('101 Red Street','26 Somerset Street','1 London Road'), - 'secaddr2' => array('Winchester','Leeds Village','Webleck'), - 'seccity' => array('London','Los Angeles','Leeds','Exeter'), - 'seccounty' => array('London','Hertfordshire','California','Buckinghamshire'), - 'secpostcode' => array('A1 1XU','AO12 3RR','E1 3XG','M1 3LF'), - 'hometel' => array('01010 123 345', '01234 546 789'), - 'worktel' => array('01010 123 345', '01234 546 789'), - 'mobtel' => array('07812 345 678'), - 'email' => array('random@email.com','not.real@gmail.com','nonsense@email.com') + 'secaddr1' => array( '101 Red Street', '26 Somerset Street', '1 London Road' ), + 'secaddr2' => array( 'Winchester', 'Leeds Village', 'Webleck' ), + 'seccity' => array( 'London', 'Los Angeles', 'Leeds', 'Exeter' ), + 'seccounty' => array( 'London', 'Hertfordshire', 'California', 'Buckinghamshire' ), + 'secpostcode' => array( 'A1 1XU', 'AO12 3RR', 'E1 3XG', 'M1 3LF' ), + 'hometel' => array( '01010 123 345', '01234 546 789' ), + 'worktel' => array( '01010 123 345', '01234 546 789' ), + 'mobtel' => array( '07812 345 678' ), + 'email' => array( 'random@email.com', 'not.real@gmail.com', 'nonsense@email.com' ), ); @@ -690,119 +746,132 @@ function zeroBS_getDemoCustomer(){ $ret['status'] = $demoData['status'][ wp_rand( 0, count( $demoData['status'] ) - 1 ) ]; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase return $ret; - } -function zeroBS_getCustomerExtraMetaVal($cID=-1,$extraMetaKey=false){ +function zeroBS_getCustomerExtraMetaVal( $cID = -1, $extraMetaKey = false ) { - if (!empty($cID) && !empty($extraMetaKey)) { + if ( ! empty( $cID ) && ! empty( $extraMetaKey ) ) { global $zbs; // quick - $cleanKey = strtolower(str_replace(' ','_',$extraMetaKey)); + $cleanKey = strtolower( str_replace( ' ', '_', $extraMetaKey ) ); - //return get_post_meta($cID, 'zbs_customer_extra_'.$cleanKey, true); - return $zbs->DAL->contacts->getContactMeta($cID,'extra_'.$cleanKey); + // return get_post_meta($cID, 'zbs_customer_extra_'.$cleanKey, true); + return $zbs->DAL->contacts->getContactMeta( $cID, 'extra_' . $cleanKey ); } return false; - } #} sets an extra meta val -function zeroBS_setCustomerExtraMetaVal($cID=-1,$extraMetaKey=false,$extraMetaVal=false){ +function zeroBS_setCustomerExtraMetaVal( $cID = -1, $extraMetaKey = false, $extraMetaVal = false ) { - if (!empty($cID) && !empty($extraMetaKey)) { + if ( ! empty( $cID ) && ! empty( $extraMetaKey ) ) { // quick - $cleanKey = strtolower(str_replace(' ','_',$extraMetaKey)); + $cleanKey = strtolower( str_replace( ' ', '_', $extraMetaKey ) ); global $zbs; - //return update_post_meta($cID, 'zbs_customer_extra_'.$cleanKey, $extraMetaVal); - return $zbs->DAL->updateMeta(ZBS_TYPE_CONTACT,$cID,'extra_'.$extraMetaKey,$extraMetaVal); + // return update_post_meta($cID, 'zbs_customer_extra_'.$cleanKey, $extraMetaVal); + return $zbs->DAL->updateMeta( ZBS_TYPE_CONTACT, $cID, 'extra_' . $extraMetaKey, $extraMetaVal ); } return false; - } -function zeroBS_updateCustomerSocialAccounts($cID=-1,$accArray=array()){ +function zeroBS_updateCustomerSocialAccounts( $cID = -1, $accArray = array() ) { + + if ( ! empty( $cID ) && is_array( $accArray ) ) { // return update_post_meta( $cID, 'zbs_customer_socials', $accArray); - if (!empty($cID) && is_array($accArray)){ //return update_post_meta($cID, 'zbs_customer_socials', $accArray); - global $zbs; #} Enact - return $zbs->DAL->contacts->addUpdateContact(array( - 'id' => $cID, - 'limitedFields' =>array( - array('key'=>'zbsc_tw','val'=>$accArray['tw'],'type'=>'%s'), - array('key'=>'zbsc_li','val'=>$accArray['li'],'type'=>'%s'), - array('key'=>'zbsc_fb','val'=>$accArray['fb'],'type'=>'%s') - ))); + return $zbs->DAL->contacts->addUpdateContact( + array( + 'id' => $cID, + 'limitedFields' => array( + array( + 'key' => 'zbsc_tw', + 'val' => $accArray['tw'], + 'type' => '%s', + ), + array( + 'key' => 'zbsc_li', + 'val' => $accArray['li'], + 'type' => '%s', + ), + array( + 'key' => 'zbsc_fb', + 'val' => $accArray['fb'], + 'type' => '%s', + ), + ), + ) + ); } return false; } +function zeroBSCRM_getCustomerFiles( $cID = -1 ) { -function zeroBSCRM_getCustomerFiles($cID=-1){ + if ( ! empty( $cID ) ) { - if (!empty($cID)){ - - global $zbs; - - //return get_post_meta($cID, 'zbs_customer_files', true); - //return $zbs->DAL->contacts->getContactMeta($cID,'files'); - return zeroBSCRM_files_getFiles('customer',$cID); + global $zbs; - } + // return get_post_meta($cID, 'zbs_customer_files', true); + // return $zbs->DAL->contacts->getContactMeta($cID,'files'); + return zeroBSCRM_files_getFiles( 'customer', $cID ); - return false; + } + return false; } // maintainIndexs keeps the files original index .e.g. 1,2 so that can match when doing portal stuff (as we're using legacy indx) -function zeroBSCRM_getCustomerPortalFiles($cID=-1){ +function zeroBSCRM_getCustomerPortalFiles( $cID = -1 ) { - if (!empty($cID)){ + if ( ! empty( $cID ) ) { - global $zbs; + global $zbs; - //return get_post_meta($cID, 'zbs_customer_files', true); - //return $zbs->DAL->contacts->getContactMeta($cID,'files'); - $ret = array(); $files = zeroBSCRM_files_getFiles('customer',$cID); - $fileIndex = 0; - if (is_array($files)) foreach ($files as $f){ - - // APPROVED portal files - if (isset($f['portal']) && $f['portal'] == 1) $ret[$fileIndex] = $f; + // return get_post_meta($cID, 'zbs_customer_files', true); + // return $zbs->DAL->contacts->getContactMeta($cID,'files'); + $ret = array(); + $files = zeroBSCRM_files_getFiles( 'customer', $cID ); + $fileIndex = 0; + if ( is_array( $files ) ) { + foreach ( $files as $f ) { + + // APPROVED portal files + if ( isset( $f['portal'] ) && $f['portal'] == 1 ) { + $ret[ $fileIndex ] = $f; + } - $fileIndex++; + ++$fileIndex; } - return $ret; - - } + } + return $ret; - return false; + } + return false; } -function zeroBSCRM_updateCustomerFiles($cID=-1,$filesArray=false){ +function zeroBSCRM_updateCustomerFiles( $cID = -1, $filesArray = false ) { - if (!empty($cID)){ - - global $zbs; + if ( ! empty( $cID ) ) { - //return update_post_meta($cID, 'zbs_customer_files', $filesArray); - return $zbs->DAL->updateMeta(ZBS_TYPE_CONTACT,$cID,'files',$filesArray); + global $zbs; - } + // return update_post_meta($cID, 'zbs_customer_files', $filesArray); + return $zbs->DAL->updateMeta( ZBS_TYPE_CONTACT, $cID, 'files', $filesArray ); - return false; + } + return false; } #} As of v1.1 can pass searchphrase @@ -813,101 +882,120 @@ function zeroBSCRM_updateCustomerFiles($cID=-1,$filesArray=false){ // ... in array like ('lead') #} 2.52+ AVOID using this, call getContacts directly plz, this is just for backward compatibility :) function zeroBS_getCustomers( - $withFullDetails=false, - $perPage=10, - $page=0, - $withInvoices=false, - $withQuotes=false, - $searchPhrase='', - $withTransactions=false, - $argsOverride=false, - $companyID=false, - $hasTagIDs='', - $inArr = '', - $withTags=false, - $withAssigned=false, - $withLastLog=false, - $sortByField='ID', - $sortOrder='DESC', - $quickFilters=false, - $ownedByID = false, - $withValues=false - ){ - /* DAL3.0: $withValues */ + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withInvoices = false, + $withQuotes = false, + $searchPhrase = '', + $withTransactions = false, + $argsOverride = false, + $companyID = false, + $hasTagIDs = '', + $inArr = '', + $withTags = false, + $withAssigned = false, + $withLastLog = false, + $sortByField = 'ID', + $sortOrder = 'DESC', + $quickFilters = false, + $ownedByID = false, + $withValues = false +) { + /* DAL3.0: $withValues */ #} Query Performance index - #global $zbsQPI; if (!isset($zbsQPI)) $zbsQPI = array(); + #global $zbsQPI; + #if (!isset($zbsQPI)) { + # $zbsQPI = array(); + #} #$zbsQPI['retrieveCustomers2getCustomers'] = zeroBSCRM_mtime_float(); // $withFullDetails = irrelevant with new DB2 (always returns) // $argsOverride CAN NO LONGER WORK :) - if ($argsOverride !== false) zeroBSCRM_DEPRECATEDMSG('Use of $argsOverride in zeroBS_getCustomers is no longer relevant (DB2)'); + if ( $argsOverride !== false ) { + zeroBSCRM_DEPRECATEDMSG( 'Use of $argsOverride in zeroBS_getCustomers is no longer relevant (DB2)' ); + } global $zbs; - // this needs translating for new dbfields: - // FOR NOW - if ($sortByField == 'post_id') $sortByField = 'ID'; - if ($sortByField == 'post_title') $sortByField = 'zbsc_lname'; - if ($sortByField == 'post_excerpt') $sortByField = 'zbsc_lname'; - - /* we need to prepend zbsc_ when not using cf */ - $custFields = $zbs->DAL->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_CONTACT)); + // this needs translating for new dbfields: + // FOR NOW + if ( $sortByField == 'post_id' ) { + $sortByField = 'ID'; + } + if ( $sortByField == 'post_title' ) { + $sortByField = 'zbsc_lname'; + } + if ( $sortByField == 'post_excerpt' ) { + $sortByField = 'zbsc_lname'; + } + + /* we need to prepend zbsc_ when not using cf */ + $custFields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_CONTACT ) ); // needs to check if field name is custom field: - $sortIsCustomField = false; if (is_array($custFields) && array_key_exists($sortByField,$custFields)) $sortIsCustomField = true; - if (!$sortIsCustomField && $sortByField != 'ID') $sortByField = 'zbsc_'.$sortByField; + $sortIsCustomField = false; + if ( is_array( $custFields ) && array_key_exists( $sortByField, $custFields ) ) { + $sortIsCustomField = true; + } + if ( ! $sortIsCustomField && $sortByField != 'ID' ) { + $sortByField = 'zbsc_' . $sortByField; + } + // catch empties + if ( empty( $sortByField ) ) { + $sortByField = 'ID'; + } + if ( empty( $sortOrder ) ) { + $sortOrder = 'desc'; + } - // catch empties - if (empty($sortByField)) $sortByField = 'ID'; - if (empty($sortOrder)) $sortOrder = 'desc'; + // legacy from dal1 + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; + } - // legacy from dal1 - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + // make ARGS + $args = array( - // make ARGS - $args = array( + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inCompany' => $companyID, + 'inArr' => $inArr, + 'quickFilters' => $quickFilters, + 'isTagged' => $hasTagIDs, + 'ownedBy' => $ownedByID, - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inCompany' => $companyID, - 'inArr' => $inArr, - 'quickFilters' => $quickFilters, - 'isTagged' => $hasTagIDs, - 'ownedBy' => $ownedByID, - - 'withCustomFields' => true, - 'withQuotes' => $withQuotes, - 'withInvoices' => $withInvoices, - 'withTransactions' => $withTransactions, - 'withLogs' => false, - 'withLastLog' => $withLastLog, - 'withTags' => $withTags, - 'withOwner' => $withAssigned, - 'withValues' => $withValues, - - 'sortByField' => $sortByField, - 'sortOrder' => $sortOrder, - 'page' => $actualPage, - 'perPage' => $perPage, - - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + 'withCustomFields' => true, + 'withQuotes' => $withQuotes, + 'withInvoices' => $withInvoices, + 'withTransactions' => $withTransactions, + 'withLogs' => false, + 'withLastLog' => $withLastLog, + 'withTags' => $withTags, + 'withOwner' => $withAssigned, + 'withValues' => $withValues, + 'sortByField' => $sortByField, + 'sortOrder' => $sortOrder, + 'page' => $actualPage, + 'perPage' => $perPage, - ); + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - // here ignore owners = true the default, because we're not really forcing ownership anywhere overall, - // when we do, we should change this/make it check - if ($ownedByID !== false) { + ); - $args['ignoreowner'] = false; + // here ignore owners = true the default, because we're not really forcing ownership anywhere overall, + // when we do, we should change this/make it check + if ( $ownedByID !== false ) { - } + $args['ignoreowner'] = false; - return $zbs->DAL->contacts->getContacts($args); + } + return $zbs->DAL->contacts->getContacts( $args ); } #} As of 2.2 - matches getCustomers but returns a total figure (no deets) @@ -916,161 +1004,168 @@ function zeroBS_getCustomers( // - trimmed returns for efficiency (is just a count really :o dirty.) // https://codex.wordpress.org/Class_Reference/WP_Query function zeroBS_getCustomersCountIncParams( - $searchPhrase='', - $argsOverride=false, - $companyID=false, - $hasTagIDs='', + $searchPhrase = '', + $argsOverride = false, + $companyID = false, + $hasTagIDs = '', $inArr = '', - $quickFilters=''){ - + $quickFilters = '' +) { // $withFullDetails = irrelevant with new DB2 (always returns) // $argsOverride CAN NO LONGER WORK :) - if ($argsOverride !== false) zeroBSCRM_DEPRECATEDMSG('Use of $argsOverride in zeroBS_getCustomersCountIncParams is no longer relevant (DB2)'); + if ( $argsOverride !== false ) { + zeroBSCRM_DEPRECATEDMSG( 'Use of $argsOverride in zeroBS_getCustomersCountIncParams is no longer relevant (DB2)' ); + } global $zbs; - // make ARGS - $args = array( - - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inCompany' => $companyID, - 'inArr' => $inArr, - 'quickFilters' => $quickFilters, - 'isTagged' => $hasTagIDs, + // make ARGS + $args = array( - // just count - 'count' =>true, + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inCompany' => $companyID, + 'inArr' => $inArr, + 'quickFilters' => $quickFilters, + 'isTagged' => $hasTagIDs, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + // just count + 'count' => true, - ); + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - return (int)$zbs->DAL->contacts->getContacts($args); + ); + return (int) $zbs->DAL->contacts->getContacts( $args ); } - - #} same as above but wrapped in contact view link -function zeroBS_getCustomerIcoLinked($cID=-1,$incName=false,$extraClasses = '',$maxSize=100){ +function zeroBS_getCustomerIcoLinked( $cID = -1, $incName = false, $extraClasses = '', $maxSize = 100 ) { - $extraHTML = ''; if ($incName){ + $extraHTML = ''; + if ( $incName ) { - $cName = zeroBS_getCustomerNameShort($cID); + $cName = zeroBS_getCustomerNameShort( $cID ); - if (!empty($cName)) $extraHTML = ''.$cName.''; + if ( ! empty( $cName ) ) { + $extraHTML = '' . $cName . ''; + } } - return ''; - + return ''; } - #} same as above but wrapped in contact view link + semantic ui label img link -function zeroBS_getCustomerIcoLinkedLabel($cID=-1){ +function zeroBS_getCustomerIcoLinkedLabel( $cID = -1 ) { - $extraHTML = ''; - $cName = zeroBS_getCustomerNameShort($cID); - if (!empty($cName)) - $extraHTML = ''.$cName.''; - else { - $cEmail = zeroBS_customerEmail($cID); - if (!empty($cEmail)) $extraHTML = ''.$cEmail.''; + $extraHTML = ''; + $cName = zeroBS_getCustomerNameShort( $cID ); + if ( ! empty( $cName ) ) { + $extraHTML = '' . $cName . ''; + } else { + $cEmail = zeroBS_customerEmail( $cID ); + if ( ! empty( $cEmail ) ) { + $extraHTML = '' . $cEmail . ''; + } } $extraClasses = ' ui image label'; - return '' . zeroBS_customerAvatarHTML($cID).$extraHTML.''; - + return '' . zeroBS_customerAvatarHTML( $cID ) . $extraHTML . ''; } - #} same as above but with no image (for non-avatar mode) -function zeroBS_getCustomerLinkedLabel($cID=-1){ +function zeroBS_getCustomerLinkedLabel( $cID = -1 ) { - $extraHTML = ''; - $cName = zeroBS_getCustomerNameShort($cID); - if (!empty($cName)) - $extraHTML = ''.$cName.''; - else { - $cEmail = zeroBS_customerEmail($cID); - if (!empty($cEmail)) $extraHTML = ''.$cEmail.''; + $extraHTML = ''; + $cName = zeroBS_getCustomerNameShort( $cID ); + if ( ! empty( $cName ) ) { + $extraHTML = '' . $cName . ''; + } else { + $cEmail = zeroBS_customerEmail( $cID ); + if ( ! empty( $cEmail ) ) { + $extraHTML = '' . $cEmail . ''; + } } // for empties, add no - if (empty($extraHTML)) $extraHTML = '#'.$cID.''; + if ( empty( $extraHTML ) ) { + $extraHTML = '#' . $cID . ''; + } $extraClasses = ' ui label'; - return '' .$extraHTML.''; - + return '' . $extraHTML . ''; } - /* Centralised delete customer func, including sub-element removal */ -function zeroBS_deleteCustomer($id=-1,$saveOrphans=true){ +function zeroBS_deleteCustomer( $id = -1, $saveOrphans = true ) { - if (!empty($id)){ + if ( ! empty( $id ) ) { global $zbs; - return $zbs->DAL->contacts->deleteContact(array('id'=>$id,'saveOrphans'=>$saveOrphans)); + return $zbs->DAL->contacts->deleteContact( + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); } return false; } - -function zeroBS_getCustomerIDWithExternalSource($externalSource='',$externalID=''){ +function zeroBS_getCustomerIDWithExternalSource( $externalSource = '', $externalID = '' ) { global $zbs; #} No empties, no random externalSources :) - if (!empty($externalSource) && !empty($externalID) && array_key_exists($externalSource,$zbs->external_sources)){ + if ( ! empty( $externalSource ) && ! empty( $externalID ) && array_key_exists( $externalSource, $zbs->external_sources ) ) { #} If here, is legit. $approvedExternalSource = $externalSource; global $zbs; - return $zbs->DAL->contacts->getContact(-1,array( - 'externalSource' => $approvedExternalSource, + return $zbs->DAL->contacts->getContact( + -1, + array( + 'externalSource' => $approvedExternalSource, 'externalSourceUID' => $externalID, - 'onlyID' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) - )); + 'onlyID' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } - return false; - } +function zeroBSCRM_getCustomerTagsByID( $cID = -1, $justIDs = false ) { -function zeroBSCRM_getCustomerTagsByID($cID=-1,$justIDs=false){ - - if (!empty($cID)){ - - global $zbs; + if ( ! empty( $cID ) ) { - return $zbs->DAL->getTagsForObjID(array( - 'objtypeid'=>ZBS_TYPE_CONTACT, - 'objid'=>$cID, - 'onlyID'=>$justIDs, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + global $zbs; - } + return $zbs->DAL->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_CONTACT, + 'objid' => $cID, + 'onlyID' => $justIDs, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); + } } - // NOTE: $objType is temporary until DB2 fully rolled out all tables -function zeroBS_getOwner($objID=-1,$withDeets=true,$objType=-1,$knownOwnerID=-1){ +function zeroBS_getOwner( $objID = -1, $withDeets = true, $objType = -1, $knownOwnerID = -1 ) { - if ($objID !== -1 && $objType !== -1){ + if ( $objID !== -1 && $objType !== -1 ) { $objType = jpcrm_upconvert_obj_type( $objType ); @@ -1078,38 +1173,40 @@ function zeroBS_getOwner($objID=-1,$withDeets=true,$objType=-1,$knownOwnerID=-1) $retObj = false; // if passed, save the db call - if ($knownOwnerID > 0){ + if ( $knownOwnerID > 0 ) { $userIDofOwner = $knownOwnerID; } else { - - $userIDofOwner = $zbs->DAL->getObjectOwner(array( - 'objID' => $objID, - 'objTypeID' => $objType - )); + + $userIDofOwner = $zbs->DAL->getObjectOwner( + array( + 'objID' => $objID, + 'objTypeID' => $objType, + ) + ); } - if (isset($userIDofOwner) && !empty($userIDofOwner)){ + if ( isset( $userIDofOwner ) && ! empty( $userIDofOwner ) ) { // check if user can be owner (is zbs admin) // check on the assign, is less performance impacting // if (! user_can($userIDofOwner,'admin_zerobs_usr') return false; - if ($withDeets){ + if ( $withDeets ) { #} Retrieve owner deets - $retObj = zeroBS_getOwnerObj($userIDofOwner); - - } else return $userIDofOwner; + $retObj = zeroBS_getOwnerObj( $userIDofOwner ); + } else { + return $userIDofOwner; + } } - - + return $retObj; - } + } return false; } @@ -1158,639 +1255,614 @@ function zeroBS_getOwnerObj( $wp_user_id = -1 ) { // NOTE - this is very generic & not to be used in future code // Use the direct $zbs->DAL->contacts->addUpdateContact code example in below rather than this generic. // kthx. -function zeroBS_setOwner($objID=-1,$ownerID=-1,$objTypeID=false){ +function zeroBS_setOwner( $objID = -1, $ownerID = -1, $objTypeID = false ) { - if ($objID !== -1 && $objTypeID !== false){ - - // here we check that the potential owner CAN even own - if (!user_can($ownerID,'admin_zerobs_usr')) return false; + if ( $objID !== -1 && $objTypeID !== false ) { + + // here we check that the potential owner CAN even own + if ( ! user_can( $ownerID, 'admin_zerobs_usr' ) ) { + return false; + } global $zbs; - return $zbs->DAL->setFieldByID(array( + return $zbs->DAL->setFieldByID( + array( - 'objID' => $objID, - 'objTypeID' => $objTypeID, + 'objID' => $objID, + 'objTypeID' => $objTypeID, - 'colname' => 'zbs_owner', - 'coldatatype' => '%d', // %d/s - 'newValue' => $ownerID, + 'colname' => 'zbs_owner', + 'coldatatype' => '%d', // %d/s + 'newValue' => $ownerID, - )); + ) + ); - } + } return false; } -function zeroBSCRM_mergeCustomers($dominantID=-1,$slaveID=-1){ +function zeroBSCRM_mergeCustomers( $dominantID = -1, $slaveID = -1 ) { - if (!empty($dominantID) && !empty($slaveID)){ + if ( ! empty( $dominantID ) && ! empty( $slaveID ) ) { - // load both - $master = zeroBS_getCustomer($dominantID); - $slave = zeroBS_getCustomer($slaveID,true,true,true); + // load both + $master = zeroBS_getCustomer( $dominantID ); + $slave = zeroBS_getCustomer( $slaveID, true, true, true ); - if (isset($master['id']) && isset($slave['id'])){ + if ( isset( $master['id'] ) && isset( $slave['id'] ) ) { - global $zbs; + global $zbs; - try { + try { - // all set, merge - $changes = array(); - $conflictingChanges = array(); + // all set, merge + $changes = array(); + $conflictingChanges = array(); $fieldPrefix = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // copy details from slave fields -> master fields - // where detail not present? - // into second address? + // copy details from slave fields -> master fields + // where detail not present? + // into second address? - $masterNewMeta = false; - $masterHasSecondAddr = false; // this'll let us copy over first from slave if empty :) - $slaveHasFirstAddr = false; $slaveHasSecondAddr = false; $slaveFirstAddrStr = ''; $slaveSecondAddrStr = ''; + $masterNewMeta = false; + $masterHasSecondAddr = false; // this'll let us copy over first from slave if empty :) + $slaveHasFirstAddr = false; + $slaveHasSecondAddr = false; + $slaveFirstAddrStr = ''; + $slaveSecondAddrStr = ''; - // if this gets filled, it'll be added as aka below - $slaveEmailAddress = false; + // if this gets filled, it'll be added as aka below + $slaveEmailAddress = false; - // because these are just arrays (in meta) - we do a kind of compare, save a new ver, - // ..and add any mismatches to conflicting changes in a meaningful way + // because these are just arrays (in meta) - we do a kind of compare, save a new ver, + // ..and add any mismatches to conflicting changes in a meaningful way - // DB2 converted these from obj[meta] -> obj + // DB2 converted these from obj[meta] -> obj - // first, just copy through slave email if present - if (isset($slave['email']) && !empty($slave['email'])) $slaveEmailAddress = $slave['email']; + // first, just copy through slave email if present + if ( isset( $slave['email'] ) && ! empty( $slave['email'] ) ) { + $slaveEmailAddress = $slave['email']; + } - // we start with the master :) + // we start with the master :) $masterNewMeta = $master; - global $zbsCustomerFields, $zbsAddressFields; + global $zbsCustomerFields, $zbsAddressFields; - // first, any empties (excluding addr) in master, get patched from secondary - foreach ($zbsCustomerFields as $fieldKey => $fieldDeets){ + // first, any empties (excluding addr) in master, get patched from secondary + foreach ( $zbsCustomerFields as $fieldKey => $fieldDeets ) { - // ignore addrs here - if (!isset($fieldDeets['migrate']) || $fieldDeets['migrate'] != 'addresses'){ - // present in master? - if (!isset($master[$fieldKey]) || empty($master[$fieldKey])){ + // ignore addrs here + if ( ! isset( $fieldDeets['migrate'] ) || $fieldDeets['migrate'] != 'addresses' ) { + // present in master? + if ( ! isset( $master[ $fieldKey ] ) || empty( $master[ $fieldKey ] ) ) { - // NOT PRESENT IN MASTER + // NOT PRESENT IN MASTER - // was not set, or empty, in master - // present in slave? - if (isset($slave[$fieldKey]) && !empty($slave[$fieldKey])){ + // was not set, or empty, in master + // present in slave? + if ( isset( $slave[ $fieldKey ] ) && ! empty( $slave[ $fieldKey ] ) ) { - // a change :) - note requires zbsc_ here for some annoying reason, leaving for now - $masterNewMeta[$fieldPrefix.$fieldKey] = $slave[$fieldKey]; + // a change :) - note requires zbsc_ here for some annoying reason, leaving for now + $masterNewMeta[ $fieldPrefix . $fieldKey ] = $slave[ $fieldKey ]; - //hopefully DB2 doesnt.. - // Does for now lol $masterNewMeta[$fieldKey] = $slave[$fieldKey]; - $changes[] = __('Copied field',"zero-bs-crm").' "'.$fieldDeets[1].'" '.__('from secondary record over main record, (main was empty).',"zero-bs-crm"); + // hopefully DB2 doesnt.. + // Does for now lol $masterNewMeta[$fieldKey] = $slave[$fieldKey]; + $changes[] = __( 'Copied field', 'zero-bs-crm' ) . ' "' . $fieldDeets[1] . '" ' . __( 'from secondary record over main record, (main was empty).', 'zero-bs-crm' ); - } + } + } else { - } else { + // if slave had value? + // (no need to worry about emails, dealt with separately) + if ( isset( $slave[ $fieldKey ] ) && ! empty( $slave[ $fieldKey ] ) && $fieldKey !== 'email' ) { - // if slave had value? - // (no need to worry about emails, dealt with separately) - if (isset($slave[$fieldKey]) && !empty($slave[$fieldKey]) && $fieldKey !== 'email'){ + // master val already present, conflicting change: + $conflictingChanges[] = __( 'Field not copied', 'zero-bs-crm' ) . ' "' . $fieldDeets[1] . '" ' . __( 'from secondary record over main record, (main had value). Value was', 'zero-bs-crm' ) . ' "' . $slave[ $fieldKey ] . '"'; - // master val already present, conflicting change: - $conflictingChanges[] = __('Field not copied',"zero-bs-crm").' "'.$fieldDeets[1].'" '.__('from secondary record over main record, (main had value). Value was',"zero-bs-crm").' "'.$slave[$fieldKey].'"'; + } + } + } else { - } + // ADDRESSES. Here we just use the foreach to check if the master has any secaddr fields + // just sets a flag used below in logic :) + if ( str_starts_with( $fieldKey, 'secaddr_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + // check presence (of any secaddr_ field) + if ( isset( $master[ $fieldKey ] ) && ! empty( $master[ $fieldKey ] ) ) { + $masterHasSecondAddr = true; + } + // does slave have secondary? + if ( isset( $slave[ $fieldKey ] ) && ! empty( $slave[ $fieldKey ] ) ) { - } else { + // clearly has (bits of) second addr + $slaveHasSecondAddr = true; - // ADDRESSES. Here we just use the foreach to check if the master has any secaddr fields - // just sets a flag used below in logic :) - if ( str_starts_with( $fieldKey, 'secaddr_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // we also build this str which'll be shown as conflicting change (so we don't "loose" this data) + if ( ! empty( $slaveSecondAddrStr ) ) { + $slaveSecondAddrStr .= ', '; + } + $slaveSecondAddrStr .= $slave[ $fieldKey ]; - // check presence (of any secaddr_ field) - if (isset($master[$fieldKey]) && !empty($master[$fieldKey])) $masterHasSecondAddr = true; + } + } else { - // does slave have secondary? - if (isset($slave[$fieldKey]) && !empty($slave[$fieldKey])) { - - // clearly has (bits of) second addr - $slaveHasSecondAddr = true; + // first address + if ( isset( $slave[ $fieldKey ] ) && ! empty( $slave[ $fieldKey ] ) ) { - // we also build this str which'll be shown as conflicting change (so we don't "loose" this data) - if (!empty($slaveSecondAddrStr)) $slaveSecondAddrStr .= ', '; - $slaveSecondAddrStr .= $slave[$fieldKey]; + // clearly has (bits of) first addr + $slaveHasFirstAddr = true; - } + // we also build this str which'll be shown as conflicting change (so we don't "loose" this data) + if ( ! empty( $slaveFirstAddrStr ) ) { + $slaveFirstAddrStr .= ', '; + } + $slaveFirstAddrStr .= $slave[ $fieldKey ]; - } else { + } + } + } + } - // first address - if (isset($slave[$fieldKey]) && !empty($slave[$fieldKey])) { + // addr's - // clearly has (bits of) first addr - $slaveHasFirstAddr = true; + // if master has no sec addr, just copy first addr from slave :) + if ( ! $masterHasSecondAddr ) { - // we also build this str which'll be shown as conflicting change (so we don't "loose" this data) - if (!empty($slaveFirstAddrStr)) $slaveFirstAddrStr .= ', '; - $slaveFirstAddrStr .= $slave[$fieldKey]; + // copy first addr from slave + foreach ( $zbsAddressFields as $addrFieldKey => $addrFieldDeets ) { - } - - } + // from slave first to master second - note requires zbsc_ here for some annoying reason, leaving for now + // Hopefully db2 doesnt + $masterNewMeta[ $fieldPrefix . 'secaddr_' . $addrFieldKey ] = $slave[ $addrFieldKey ]; + // Does for now lol $masterNewMeta['secaddr_'.$addrFieldKey] = $slave[$addrFieldKey]; - } + } + $changes[] = __( 'Copied address from secondary record into "secondary address" for main record', 'zero-bs-crm' ); - } + // any second addr from slave just goes into logs + if ( $slaveHasSecondAddr ) { + // provide old addr string + $conflictingChanges[] = __( 'Address not copied. Secondary address from secondary record could not be copied (master already had two addresses).', 'zero-bs-crm' ) . "\r\n" . __( 'Address', 'zero-bs-crm' ) . ': ' . "\r\n" . $slaveSecondAddrStr; - // addr's + } + } else { - // if master has no sec addr, just copy first addr from slave :) - if (!$masterHasSecondAddr){ + // master already has two addresses, dump (any) secondary addresses into conflicting changes - // copy first addr from slave - foreach ($zbsAddressFields as $addrFieldKey => $addrFieldDeets){ + if ( $slaveHasFirstAddr ) { - // from slave first to master second - note requires zbsc_ here for some annoying reason, leaving for now - // Hopefully db2 doesnt - $masterNewMeta[$fieldPrefix.'secaddr_'.$addrFieldKey] = $slave[$addrFieldKey]; - // Does for now lol $masterNewMeta['secaddr_'.$addrFieldKey] = $slave[$addrFieldKey]; + // provide old addr string + $conflictingChanges[] = __( 'Address not copied. Address from secondary record could not be copied (master already had two addresses).', 'zero-bs-crm' ) . "\r\n" . __( 'Address', 'zero-bs-crm' ) . ': ' . "\r\n" . $slaveFirstAddrStr; + } + if ( $slaveHasSecondAddr ) { - } - $changes[] = __('Copied address from secondary record into "secondary address" for main record',"zero-bs-crm"); + // provide old addr string + $conflictingChanges[] = __( 'Address not copied. Secondary address from secondary record could not be copied (master already had two addresses).', 'zero-bs-crm' ) . "\r\n" . __( 'Address', 'zero-bs-crm' ) . ': ' . "\r\n" . $slaveSecondAddrStr; - // any second addr from slave just goes into logs - if ($slaveHasSecondAddr){ + } + } - // provide old addr string - $conflictingChanges[] = __('Address not copied. Secondary address from secondary record could not be copied (master already had two addresses).',"zero-bs-crm")."\r\n".__('Address',"zero-bs-crm").': '."\r\n".$slaveSecondAddrStr; + // assign social profiles from slave -> master + // GET THESE BEFORE updating! + $masterSocial = $zbs->DAL->contacts->getContactSocials( $dominantID ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $slaveSocial = $zbs->DAL->contacts->getContactSocials( $slaveID ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + // UPDATE MASTER META: + zeroBS_addUpdateCustomer( $dominantID, $masterNewMeta, '', '', '', false, false, false, -1, $fieldPrefix ); + $masterNewSocial = $masterSocial; - } else { + global $zbsSocialAccountTypes; - // master already has two addresses, dump (any) secondary addresses into conflicting changes + if ( count( $zbsSocialAccountTypes ) > 0 ) { - if ($slaveHasFirstAddr){ + foreach ( $zbsSocialAccountTypes as $socialKey => $socialAccType ) { - // provide old addr string - $conflictingChanges[] = __('Address not copied. Address from secondary record could not be copied (master already had two addresses).',"zero-bs-crm")."\r\n".__('Address',"zero-bs-crm").': '."\r\n".$slaveFirstAddrStr; + // master / slave has this acc? + // for simplicity (not perf.) we grab which has which, first + $masterHas = false; + $slaveHas = false; + if ( is_array( $masterSocial ) && isset( $masterSocial[ $socialKey ] ) && ! empty( $masterSocial[ $socialKey ] ) ) { + $masterHas = true; + } + if ( is_array( $slaveSocial ) && isset( $slaveSocial[ $socialKey ] ) && ! empty( $slaveSocial[ $socialKey ] ) ) { + $slaveHas = true; + } + // what's up. + if ( $masterHas && $slaveHas ) { - } - if ($slaveHasSecondAddr){ + // conflicting change + $conflictingChanges[] = __( 'Social account not copied.', 'zero-bs-crm' ) . ' "' . $socialAccType['name'] . '" of "' . $slaveSocial[ $socialKey ] . '" ' . __( 'from secondary record (master already has a ', 'zero-bs-crm' ) . $socialAccType['name'] . ' ' . __( 'account.', 'zero-bs-crm' ); - // provide old addr string - $conflictingChanges[] = __('Address not copied. Secondary address from secondary record could not be copied (master already had two addresses).',"zero-bs-crm")."\r\n".__('Address',"zero-bs-crm").': '."\r\n".$slaveSecondAddrStr; + } elseif ( $masterHas && ! $slaveHas ) { + // no change - } - } + } elseif ( $slaveHas && ! $masterHas ) { + // copy slave -> master + $masterNewSocial[ $socialKey ] = $slaveSocial[ $socialKey ]; + $changes[] = __( 'Copied social account from secondary record into main record', 'zero-bs-crm' ) . ' (' . $socialAccType['name'] . ').'; - // assign social profiles from slave -> master - // GET THESE BEFORE updating! - $masterSocial = $zbs->DAL->contacts->getContactSocials( $dominantID ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - $slaveSocial = $zbs->DAL->contacts->getContactSocials( $slaveID ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - - // UPDATE MASTER META: - zeroBS_addUpdateCustomer($dominantID,$masterNewMeta,'','','',false,false,false,-1,$fieldPrefix); - - $masterNewSocial = $masterSocial; - - global $zbsSocialAccountTypes; - - if (count($zbsSocialAccountTypes) > 0) { - - foreach ($zbsSocialAccountTypes as $socialKey => $socialAccType){ - - // master / slave has this acc? - // for simplicity (not perf.) we grab which has which, first - $masterHas = false; $slaveHas = false; - if (is_array($masterSocial) && isset($masterSocial[$socialKey]) && !empty($masterSocial[$socialKey])) { $masterHas = true; } - if (is_array($slaveSocial) && isset($slaveSocial[$socialKey]) && !empty($slaveSocial[$socialKey])) { $slaveHas = true; } - - // what's up. - if ($masterHas && $slaveHas){ - - // conflicting change - $conflictingChanges[] = __('Social account not copied.',"zero-bs-crm").' "'.$socialAccType['name'].'" of "'.$slaveSocial[$socialKey].'" '.__('from secondary record (master already has a ',"zero-bs-crm").$socialAccType['name'].' '.__('account.',"zero-bs-crm"); - - - } elseif ($masterHas && !$slaveHas){ - - // no change - - } elseif ($slaveHas && !$masterHas){ - - // copy slave -> master - $masterNewSocial[$socialKey] = $slaveSocial[$socialKey]; - $changes[] = __('Copied social account from secondary record into main record',"zero-bs-crm").' ('.$socialAccType['name'].').'; - - - } - - } - - // UPDATE SOCIAL - zeroBS_updateCustomerSocialAccounts($dominantID,$masterNewSocial); + } + } - } + // UPDATE SOCIAL + zeroBS_updateCustomerSocialAccounts( $dominantID, $masterNewSocial ); + } - // assign files from slave -> master + // assign files from slave -> master - /* Array + /* + Array ( - [0] => Array - ( - [file] => /app/public/wp-content/uploads/zbscrm-store/aa250965422e9aea-Document-20243.pdf - [url] => http://zbsphp5.dev/wp-content/uploads/zbscrm-store/aa250965422e9aea-Document-20243.pdf - [type] => application/pdf - [error] => - [priv] => 1 - ) + [0] => Array + ( + [file] => /app/public/wp-content/uploads/zbscrm-store/aa250965422e9aea-Document-20243.pdf + [url] => http://zbsphp5.dev/wp-content/uploads/zbscrm-store/aa250965422e9aea-Document-20243.pdf + [type] => application/pdf + [error] => + [priv] => 1 + ) ) */ - $slaveFiles = zeroBSCRM_getCustomerFiles($slaveID); - - if (is_array($slaveFiles) && count($slaveFiles) > 0){ - - $masterFiles = zeroBSCRM_getCustomerFiles($dominantID); - - if (!is_array($masterFiles)) $masterFiles = array(); - - foreach ($slaveFiles as $zbsFile){ - - // add - $masterFiles[] = $zbsFile; - - // changelog - - $filename = basename($zbsFile['file']); + $slaveFiles = zeroBSCRM_getCustomerFiles( $slaveID ); - // if in privatised system, ignore first hash in name - if (isset($zbsFile['priv'])){ + if ( is_array( $slaveFiles ) && count( $slaveFiles ) > 0 ) { - $filename = substr($filename,strpos($filename, '-')+1); - } - - $changes[] = __('Moved file to main record',"zero-bs-crm").' ('.$filename.')'; - - - } - - // save master files - zeroBSCRM_updateCustomerFiles($dominantID,$masterFiles); - - - } - - // assign company from slave -> master - - $masterCompany = zeroBS_getCustomerCompanyID($dominantID); - $slaveCompany = zeroBS_getCustomerCompanyID($slaveID); - if (empty($masterCompany)){ - - // slave co present, update main - if (!empty($slaveCompany)){ - - zeroBS_setCustomerCompanyID($dominantID,$slaveCompany); - $changes[] = __('Assigned main record to secondary record\'s '.jpcrm_label_company(),"zero-bs-crm").' (#'.$slaveCompany.').'; - - - } - - - } else { - - // master has co already, does slave? - if (!empty($slaveCompany) && $slaveCompany != $masterCompany){ - - // conflicting change - $conflictingChanges[] = __('Secondary contact was assigned to '.jpcrm_label_company().', whereas main record was assigned to another '.jpcrm_label_company().'.',"zero-bs-crm").' (#'.$slaveCompany.').'; - - - } - - } - - // assign quotes from slave -> master - - // got quotes? - if (is_array($slave['quotes']) && count($slave['quotes']) > 0){ - - $quoteOffset = zeroBSCRM_getQuoteOffset(); - - foreach ($slave['quotes'] as $quote){ - - // id for passing to logs - $qID = ''; - #TRANSITIONTOMETANO - if (isset($quote['zbsid'])) $qID = $quote['zbsid']; - - // for quotes, we just "switch" the owner meta :) - zeroBSCRM_changeQuoteCustomer($quote['id'],$dominantID); - $changes[] = __('Assigned quote from secondary record onto main record',"zero-bs-crm").' (#'.$qID.').'; - - - } + $masterFiles = zeroBSCRM_getCustomerFiles( $dominantID ); + if ( ! is_array( $masterFiles ) ) { + $masterFiles = array(); + } + foreach ( $slaveFiles as $zbsFile ) { - } // / has quotes + // add + $masterFiles[] = $zbsFile; - // assign invs from slave -> master + // changelog - // got invoices? - if (is_array($slave['invoices']) && count($slave['invoices']) > 0){ + $filename = basename( $zbsFile['file'] ); - foreach ($slave['invoices'] as $invoice){ + // if in privatised system, ignore first hash in name + if ( isset( $zbsFile['priv'] ) ) { - // for invs, we just "switch" the owner meta :) - zeroBSCRM_changeInvoiceCustomer($invoice['id'],$dominantID); - $changes[] = __('Assigned invoice from secondary record onto main record',"zero-bs-crm").' (#'.$invoice['id'].').'; - + $filename = substr( $filename, strpos( $filename, '-' ) + 1 ); + } - } + $changes[] = __( 'Moved file to main record', 'zero-bs-crm' ) . ' (' . $filename . ')'; + } - } // / has invoices + // save master files + zeroBSCRM_updateCustomerFiles( $dominantID, $masterFiles ); + } - // assign trans from slave -> master + // assign company from slave -> master - // got invoices? - if (is_array($slave['transactions']) && count($slave['transactions']) > 0){ + $masterCompany = zeroBS_getCustomerCompanyID( $dominantID ); + $slaveCompany = zeroBS_getCustomerCompanyID( $slaveID ); + if ( empty( $masterCompany ) ) { - foreach ($slave['transactions'] as $transaction){ + // slave co present, update main + if ( ! empty( $slaveCompany ) ) { - // for trans, we just "switch" the owner meta :) - zeroBSCRM_changeTransactionCustomer($transaction['id'],$dominantID); - $changes[] = __('Assigned transaction from secondary record onto main record',"zero-bs-crm").' (#'.$transaction['id'].').'; - + zeroBS_setCustomerCompanyID( $dominantID, $slaveCompany ); + $changes[] = __( 'Assigned main record to secondary record\'s ' . jpcrm_label_company(), 'zero-bs-crm' ) . ' (#' . $slaveCompany . ').'; - } + } + } else { + // master has co already, does slave? + if ( ! empty( $slaveCompany ) && $slaveCompany != $masterCompany ) { - } // / has invoices + // conflicting change + $conflictingChanges[] = __( 'Secondary contact was assigned to ' . jpcrm_label_company() . ', whereas main record was assigned to another ' . jpcrm_label_company() . '.', 'zero-bs-crm' ) . ' (#' . $slaveCompany . ').'; + } + } + // assign quotes from slave -> master - // assign events from slave -> master + // got quotes? + if ( is_array( $slave['quotes'] ) && count( $slave['quotes'] ) > 0 ) { - // get events - $events = zeroBS_getEventsByCustomerID($slaveID,true,10000,0); - if (is_array($events) && count($events) > 0){ + $quoteOffset = zeroBSCRM_getQuoteOffset(); - foreach ($events as $event){ + foreach ( $slave['quotes'] as $quote ) { - // for events, we just "switch" the meta val :) - zeroBSCRM_changeEventCustomer($event['id'],$dominantID); - $changes[] = __( 'Assigned task from secondary record onto main record', 'zero-bs-crm' ) . ' (#' . $event['id'] . ').'; - + // id for passing to logs + $qID = ''; + #TRANSITIONTOMETANO + if ( isset( $quote['zbsid'] ) ) { + $qID = $quote['zbsid']; + } - } + // for quotes, we just "switch" the owner meta :) + zeroBSCRM_changeQuoteCustomer( $quote['id'], $dominantID ); + $changes[] = __( 'Assigned quote from secondary record onto main record', 'zero-bs-crm' ) . ' (#' . $qID . ').'; + } + } // / has quotes + // assign invs from slave -> master - } // / has invoices + // got invoices? + if ( is_array( $slave['invoices'] ) && count( $slave['invoices'] ) > 0 ) { + foreach ( $slave['invoices'] as $invoice ) { + // for invs, we just "switch" the owner meta :) + zeroBSCRM_changeInvoiceCustomer( $invoice['id'], $dominantID ); + $changes[] = __( 'Assigned invoice from secondary record onto main record', 'zero-bs-crm' ) . ' (#' . $invoice['id'] . ').'; - // assign logs(?) from slave -> master + } + } // / has invoices - // for now save these as a random text meta against customer (not sure how to expose as of yet, but don't want to loose) - $slaveLogs = zeroBSCRM_getContactLogs($slaveID,true,10000,0); // id created name meta - if (is_array($slaveLogs) && count($slaveLogs) > 0){ + // assign trans from slave -> master - /* in fact, just save as json encode :D - rough but quicker - // brutal str builder. - $logStr = ''; + // got invoices? + if ( is_array( $slave['transactions'] ) && count( $slave['transactions'] ) > 0 ) { - foreach ($slaveLogs as $log){ + foreach ( $slave['transactions'] as $transaction ) { - if (!empty($logStr)) $logStr .= "\r\n"; + // for trans, we just "switch" the owner meta :) + zeroBSCRM_changeTransactionCustomer( $transaction['id'], $dominantID ); + $changes[] = __( 'Assigned transaction from secondary record onto main record', 'zero-bs-crm' ) . ' (#' . $transaction['id'] . ').'; + } + } // / has invoices - } */ + // assign events from slave -> master - //update_post_meta($dominantID, 'zbs_merged_customer_log_bk_'.time(), json_encode($slaveLogs)); - // no $change here, as this is kinda secret, kthx - $zbs->DAL->updateMeta(ZBS_TYPE_CONTACT,$dominantID,'merged_customer_log_bk_'.time(),$slaveLogs); + // get events + $events = zeroBS_getEventsByCustomerID( $slaveID, true, 10000, 0 ); + if ( is_array( $events ) && count( $events ) > 0 ) { - } + foreach ( $events as $event ) { + // for events, we just "switch" the meta val :) + zeroBSCRM_changeEventCustomer( $event['id'], $dominantID ); + $changes[] = __( 'Assigned task from secondary record onto main record', 'zero-bs-crm' ) . ' (#' . $event['id'] . ').'; - // assign tags(?) from slave -> master - - // get slave tags as ID array - $slaveTagsIDs = zeroBSCRM_getCustomerTagsByID($slaveID,true); - if (is_array($slaveTagsIDs) && count($slaveTagsIDs) > 0){ + } + } // / has invoices - // add tags to master (append mode) - //wp_set_object_terms($dominantID, $slaveTagsIDs, 'zerobscrm_customertag', true ); - $zbs->DAL->addUpdateObjectTags(array( - 'objid' => $dominantID, - 'objtype' => ZBS_TYPE_CONTACT, - 'tagIDs' => $slaveTagsIDs, - 'mode' => 'append' - )); - $changes[] = __('Tagged main record with',"zero-bs-crm").' '.count($slaveTagsIDs).' '.__('tags from secondary record.',"zero-bs-crm"); + // assign logs(?) from slave -> master + // for now save these as a random text meta against customer (not sure how to expose as of yet, but don't want to loose) + $slaveLogs = zeroBSCRM_getContactLogs( $slaveID, true, 10000, 0 ); // id created name meta + if ( is_array( $slaveLogs ) && count( $slaveLogs ) > 0 ) { - } + /* + in fact, just save as json encode :D - rough but quicker + // brutal str builder. + $logStr = ''; - // AKA / alias + foreach ( $slaveLogs as $log){ - // second email -> alias first - if (!empty($slaveEmailAddress)){ + if ( !empty( $logStr)) $logStr .= "\r\n"; + } */ - // add as alias - zeroBS_addCustomerAlias($dominantID,$slaveEmailAddress); - $changes[] = __('Added secondary record email as alias/aka of main record',"zero-bs-crm").' ('.$slaveEmailAddress.')'; + // update_post_meta($dominantID, 'zbs_merged_customer_log_bk_'.time(), json_encode($slaveLogs)); + // no $change here, as this is kinda secret, kthx + $zbs->DAL->updateMeta( ZBS_TYPE_CONTACT, $dominantID, 'merged_customer_log_bk_' . time(), $slaveLogs ); + } - } + // assign tags(?) from slave -> master + // get slave tags as ID array + $slaveTagsIDs = zeroBSCRM_getCustomerTagsByID( $slaveID, true ); + if ( is_array( $slaveTagsIDs ) && count( $slaveTagsIDs ) > 0 ) { + // add tags to master (append mode) + // wp_set_object_terms($dominantID, $slaveTagsIDs, 'zerobscrm_customertag', true ); + $zbs->DAL->addUpdateObjectTags( + array( + 'objid' => $dominantID, + 'objtype' => ZBS_TYPE_CONTACT, + 'tagIDs' => $slaveTagsIDs, + 'mode' => 'append', + ) + ); + $changes[] = __( 'Tagged main record with', 'zero-bs-crm' ) . ' ' . count( $slaveTagsIDs ) . ' ' . __( 'tags from secondary record.', 'zero-bs-crm' ); - // Customer image + } - //(for now, left to die) + // AKA / alias + // second email -> alias first + if ( ! empty( $slaveEmailAddress ) ) { - // delete slave - zeroBS_deleteCustomer($slaveID,false); - $changes[] = __('Removed secondary record',"zero-bs-crm").' (#'.$slaveID.')'; + // add as alias + zeroBS_addCustomerAlias( $dominantID, $slaveEmailAddress ); + $changes[] = __( 'Added secondary record email as alias/aka of main record', 'zero-bs-crm' ) . ' (' . $slaveEmailAddress . ')'; - // assign log for changes + conflicting changes + } - // strbuild - $shortDesc ='"'.$slave['name'].'" (#'.$slave['id'].') '.__('into this record',"zero-bs-crm"); - $longDesc = ''; + // Customer image - // changes - if (is_array($changes) && count($changes) > 0) { + // (for now, left to die) - $longDesc .= ''.__('Record Changes',"zero-bs-crm").':
'; + // delete slave + zeroBS_deleteCustomer( $slaveID, false ); + $changes[] = __( 'Removed secondary record', 'zero-bs-crm' ) . ' (#' . $slaveID . ')'; - // cycle through em - foreach ($changes as $c){ + // assign log for changes + conflicting changes - $longDesc .= '
'.$c; - - } + // strbuild + $shortDesc = '"' . $slave['name'] . '" (#' . $slave['id'] . ') ' . __( 'into this record', 'zero-bs-crm' ); + $longDesc = ''; - } else { + // changes + if ( is_array( $changes ) && count( $changes ) > 0 ) { - $longDesc .= ''.__('No Changes',"zero-bs-crm").''; + $longDesc .= '' . __( 'Record Changes', 'zero-bs-crm' ) . ':
'; - } + // cycle through em + foreach ( $changes as $c ) { - // conflicting changes - if (is_array($conflictingChanges) && count($conflictingChanges) > 0) { + $longDesc .= '
' . $c; - $longDesc .= '
=============================
'.__('Conflicting Changes',"zero-bs-crm").':
'; + } + } else { - // cycle through em - foreach ($conflictingChanges as $c){ + $longDesc .= '' . __( 'No Changes', 'zero-bs-crm' ) . ''; - $longDesc .= '
'.$c; + } - } + // conflicting changes + if ( is_array( $conflictingChanges ) && count( $conflictingChanges ) > 0 ) { - } else { + $longDesc .= '
=============================
' . __( 'Conflicting Changes', 'zero-bs-crm' ) . ':
'; - $longDesc .= '
=============================
'.__('No Conflicting Changes',"zero-bs-crm").''; + // cycle through em + foreach ( $conflictingChanges as $c ) { - } + $longDesc .= '
' . $c; + } + } else { - // MASTER LOG :D - zeroBS_addUpdateContactLog($dominantID,-1,-1,array( - 'type' => 'Bulk Action: Merge', - 'shortdesc' => $shortDesc, - 'longdesc' => $longDesc) - ); + $longDesc .= '
=============================
' . __( 'No Conflicting Changes', 'zero-bs-crm' ) . ''; - return true; + } - } catch (Exception $e){ + // MASTER LOG :D + zeroBS_addUpdateContactLog( + $dominantID, + -1, + -1, + array( + 'type' => 'Bulk Action: Merge', + 'shortdesc' => $shortDesc, + 'longdesc' => $longDesc, + ) + ); - // failed somehow! - echo 'ERROR:'.$e->getMessage(); + return true; - } + } catch ( Exception $e ) { - } // / if id's + // failed somehow! + echo 'ERROR:' . $e->getMessage(); - } + } + } // / if id's - return false; + } + return false; } function zeroBS_addUpdateCustomer( - - $cID = -1, - $cFields = array(), - - $externalSource='', - $externalID='', - $customerDate='', - - $fallBackLog = false, - $extraMeta = false, - $automatorPassthrough = false, - $owner = -1, - - $metaBuilderPrefix = 'zbsc_' - - ){ + $cID = -1, + $cFields = array(), + $externalSource = '', + $externalID = '', + $customerDate = '', + $fallBackLog = false, + $extraMeta = false, + $automatorPassthrough = false, + $owner = -1, + $metaBuilderPrefix = 'zbsc_' +) { #} return $ret = false; - if (isset($cFields) && count($cFields) > 0){ + if ( isset( $cFields ) && count( $cFields ) > 0 ) { #} New flag - $newCustomer = false; $originalStatus = ''; + $newCustomer = false; + $originalStatus = ''; global $zbs; + if ( $cID > 0 ) { - if ($cID > 0){ - - #} Retrieve / check? - $postID = $cID; + #} Retrieve / check? + $postID = $cID; - #} Build "existing meta" to pass, (so we only update fields pushed here) - $existingMeta = $zbs->DAL->contacts->getContact($postID,array()); + #} Build "existing meta" to pass, (so we only update fields pushed here) + $existingMeta = $zbs->DAL->contacts->getContact( $postID, array() ); + $originalDate = time(); + if ( isset( $existingMeta ) && is_array( $existingMeta ) && isset( $existingMeta['createduts'] ) && ! empty( $existingMeta['createduts'] ) ) { + $originalDate = $existingMeta['createduts']; + } - $originalDate = time(); - if (isset($existingMeta) && is_array($existingMeta) && isset($existingMeta['createduts']) && !empty($existingMeta['createduts'])) $originalDate = $existingMeta['createduts']; - - if (!empty($customerDate) && $customerDate != ''){ + if ( ! empty( $customerDate ) && $customerDate != '' ) { - #} DATE PASSED TO THE FUNCTION - $customerDateTimeStamp = strtotime($customerDate); - #} ORIGINAL POST CREATION DATE - // no need, db2 = UTS $originalDateTimeStamp = strtotime($originalDate); - $originalDateTimeStamp = $originalDate; + #} DATE PASSED TO THE FUNCTION + $customerDateTimeStamp = strtotime( $customerDate ); + #} ORIGINAL POST CREATION DATE + // no need, db2 = UTS $originalDateTimeStamp = strtotime($originalDate); + $originalDateTimeStamp = $originalDate; - #} Compare, if $customerDateTimeStamp < then update with passed date - if($customerDateTimeStamp < $originalDateTimeStamp){ + #} Compare, if $customerDateTimeStamp < then update with passed date + if ( $customerDateTimeStamp < $originalDateTimeStamp ) { - // straight in there :) - $zbs->DAL->contacts->addUpdateContact(array( - 'id' => $postID, - 'limitedFields' =>array( - array('key'=>'zbsc_created','val'=>$customerDateTimeStamp,'type'=>'%d') - ))); - } + // straight in there :) + $zbs->DAL->contacts->addUpdateContact( + array( + 'id' => $postID, + 'limitedFields' => array( + array( + 'key' => 'zbsc_created', + 'val' => $customerDateTimeStamp, + 'type' => '%d', + ), + ), + ) + ); } + } - // WH changed 20/05/18 - // 20/05/18 - Previously this would reload the EXISTING database data + // WH changed 20/05/18 + // 20/05/18 - Previously this would reload the EXISTING database data // THEN 'override' any passed fields // THEN save that down // ... this was required when we used old meta objs. (pre db2) // ... so if we're now DAL2, we can do away with that and simply pass what's to be updated and mode do_not_update_blanks $existingMeta = array(); + } else { - } else { + // DB2: Probably can rethink this whole func, (do we even need it?) e.g. header post mentality used here + // for now I've just edited in place, but def refactor in time - // DB2: Probably can rethink this whole func, (do we even need it?) e.g. header post mentality used here - // for now I've just edited in place, but def refactor in time - - #} Set flag - $newCustomer = true; - - #} Set up empty meta arr + #} Set flag + $newCustomer = true; - #} DATE PASSED TO THE FUNCTION - $customerDateTimeStamp = strtotime($customerDate); - #} DAL2 needs timestamp :) - $existingMeta = array('created' => $customerDateTimeStamp); + #} Set up empty meta arr - } + #} DATE PASSED TO THE FUNCTION + $customerDateTimeStamp = strtotime( $customerDate ); + #} DAL2 needs timestamp :) + $existingMeta = array( 'created' => $customerDateTimeStamp ); + + } - #} Build using centralised func below, passing any existing meta (updates not overwrites) - $zbsCustomerMeta = zeroBS_buildContactMeta( $cFields, $existingMeta, $metaBuilderPrefix, '', true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + #} Build using centralised func below, passing any existing meta (updates not overwrites) + $zbsCustomerMeta = zeroBS_buildContactMeta( $cFields, $existingMeta, $metaBuilderPrefix, '', true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $we_have_tags = false; // set to false.. duh.. @@ -1847,94 +1919,94 @@ function zeroBS_addUpdateCustomer( if ( ! empty( $tag_id ) ) { $zbsCustomerMeta['tags'][] = $tag_id; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - } } } + #} Add external source/externalid + #} No empties, no random externalSources :) + $extSourceArr = -1; + $approvedExternalSource = ''; #} As this is passed to automator :) + if ( ! empty( $externalSource ) && ! empty( $externalID ) && array_key_exists( $externalSource, $zbs->external_sources ) ) { - #} Add external source/externalid - #} No empties, no random externalSources :) - $extSourceArr = -1; $approvedExternalSource = ''; #} As this is passed to automator :) - if (!empty($externalSource) && !empty($externalID) && array_key_exists($externalSource,$zbs->external_sources)){ - - #} If here, is legit. - $approvedExternalSource = $externalSource; - - #} Add/Update record flag - // 2.4+ Migrated away from this method to new update_post_meta($postID, 'zbs_customer_ext_'.$approvedExternalSource, $externalID); - // 2.52+ Moved to new DAL method :) - - $extSourceArr = array( - 'source' => $approvedExternalSource, - 'uid' => $externalID - ); - - // add/update - // DB2, this is just used below :)zeroBS_updateExternalSource($postID,$extSourceArr); - $zbsCustomerMeta['externalSources'] = array($extSourceArr); - - } #} Otherwise will just be a random customer no ext source + #} If here, is legit. + $approvedExternalSource = $externalSource; - #} Got owner? - if ($owner !== -1) $zbsCustomerMeta['owner'] = $owner; + #} Add/Update record flag + // 2.4+ Migrated away from this method to new update_post_meta($postID, 'zbs_customer_ext_'.$approvedExternalSource, $externalID); + // 2.52+ Moved to new DAL method :) + $extSourceArr = array( + 'source' => $approvedExternalSource, + 'uid' => $externalID, + ); - #} Update record (All IA is now fired intrinsicly ) - // DB2 update_post_meta($postID, 'zbs_customer_meta', $zbsCustomerMeta); - return $zbs->DAL->contacts->addUpdateContact(array( - 'id' => $cID, - 'data' => $zbsCustomerMeta, - 'extraMeta' => $extraMeta, - 'automatorPassthrough' => $automatorPassthrough, - 'fallBackLog' => $fallBackLog - )); + // add/update + // DB2, this is just used below :)zeroBS_updateExternalSource($postID,$extSourceArr); + $zbsCustomerMeta['externalSources'] = array( $extSourceArr ); + } #} Otherwise will just be a random customer no ext source - /* This now get's passed above, and dealt with by DAL - #} Any extra meta keyval pairs? - $confirmedExtraMeta = false; - if (isset($extraMeta) && is_array($extraMeta)) { + #} Got owner? + if ( $owner !== -1 ) { + $zbsCustomerMeta['owner'] = $owner; + } - $confirmedExtraMeta = array(); + #} Update record (All IA is now fired intrinsicly ) + // DB2 update_post_meta($postID, 'zbs_customer_meta', $zbsCustomerMeta); + return $zbs->DAL->contacts->addUpdateContact( + array( + 'id' => $cID, + 'data' => $zbsCustomerMeta, + 'extraMeta' => $extraMeta, + 'automatorPassthrough' => $automatorPassthrough, + 'fallBackLog' => $fallBackLog, + ) + ); - foreach ($extraMeta as $k => $v){ + /* + This now get's passed above, and dealt with by DAL + #} Any extra meta keyval pairs? + $confirmedExtraMeta = false; + if ( isset( $extraMeta) && is_array( $extraMeta) ) { - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + $confirmedExtraMeta = array(); - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $zbs->DAL->updateMeta(ZBS_TYPE_CONTACT,$postID,'extra_'.$cleanKey,$v); + foreach ( $extraMeta as $k => $v){ - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $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); + $zbs->DAL->updateMeta(ZBS_TYPE_CONTACT,$postID,'extra_'.$cleanKey,$v); - } */ + #} Add it to this, which passes to IA + $confirmedExtraMeta[$cleanKey] = $v; + } - /* NOW DEALT WITH IN DAL2 :) + } */ + /* + NOW DEALT WITH IN DAL2 :) - #} INTERNAL AUTOMATOR - #} & + #} INTERNAL AUTOMATOR + #} & #} FALLBACKS - if ($newCustomer){ + if ( $newCustomer){ #} Add to automator zeroBSCRM_FireInternalAutomator('customer.new',array( - 'id'=>$postID, - 'customerMeta'=>$zbsCustomerMeta, - 'extsource'=>$approvedExternalSource, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'customerExtraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); - + 'id'=>$postID, + 'customerMeta'=>$zbsCustomerMeta, + 'extsource'=>$approvedExternalSource, + 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'customerExtraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) + )); - // (WH) Moved this to fire on the IA... + // (WH) Moved this to fire on the IA... // do_action('zbs_new_customer', $postID); //fire the hook here... } else { @@ -1942,21 +2014,23 @@ function zeroBS_addUpdateCustomer( #} Customer Update here (automator)? #} TODO - - #} FALLBACK + #} 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 ( - isset($fallBackLog) && is_array($fallBackLog) + isset($fallBackLog) && is_array($fallBackLog) && isset($fallBackLog['type']) && !empty($fallBackLog['type']) && isset($fallBackLog['shortdesc']) && !empty($fallBackLog['shortdesc']) - ){ + ) { #} Brutal add, maybe validate more?! #} Long desc if present: - $zbsNoteLongDesc = ''; if (isset($fallBackLog['longdesc']) && !empty($fallBackLog['longdesc'])) $zbsNoteLongDesc = $fallBackLog['longdesc']; + $zbsNoteLongDesc = ''; + if ( isset( $fallBackLog['longdesc']) && !empty( $fallBackLog['longdesc']) ) { + $zbsNoteLongDesc = $fallBackLog['longdesc']; + } #} Only raw checked... but proceed. $newOrUpdatedLogID = zeroBS_addUpdateContactLog($postID,-1,-1,array( @@ -1966,467 +2040,462 @@ function zeroBS_addUpdateCustomer( 'longdesc' => $zbsNoteLongDesc )); - } - - - // catch dirty flag (update of status) (note, after update_post_meta - as separate) - //if (isset($_POST['zbsc_status_dirtyflag']) && $_POST['zbsc_status_dirtyflag'] == "1"){ + // catch dirty flag (update of status) (note, after update_post_meta - as separate) + //if (isset($_POST['zbsc_status_dirtyflag']) && $_POST['zbsc_status_dirtyflag'] == "1"){ // actually here, it's set above - if (isset($statusChange) && is_array($statusChange)){ - - // status has changed + if ( isset( $statusChange) && is_array( $statusChange)){ - // IA - zeroBSCRM_FireInternalAutomator('customer.status.update',array( - 'id'=>$postID, - 'againstid' => $postID, - 'userMeta'=> $zbsCustomerMeta, - 'from' => $statusChange['from'], - 'to' => $statusChange['to'] - )); + // status has changed - } + // IA + zeroBSCRM_FireInternalAutomator('customer.status.update',array( + 'id'=>$postID, + 'againstid' => $postID, + 'userMeta'=> $zbsCustomerMeta, + 'from' => $statusChange['from'], + 'to' => $statusChange['to'] + )); + } } */ - - #} REQ? #} MAKE SURE if you change any post_name features you also look at: "NAMECHANGES" in this file (when a post updates it'll auto replace these...) - #$newCName = zeroBS_customerName('',$zbsMeta,true,false) - + #$newCName = zeroBS_customerName('',$zbsMeta,true,false) #} Return customerID if success :) - //$ret = $postID; - - + // $ret = $postID; } - - return $ret; - } - -/* ====================================================== - Contact -> aliases - ====================================================== */ +/* +====================================================== + Contact -> aliases + ====================================================== */ #} See if already in use/exists -function zeroBS_canUseCustomerAlias($alias=''){ +function zeroBS_canUseCustomerAlias( $alias = '' ) { // now can call this generic: - return zeroBS_canUseAlias(ZBS_TYPE_CONTACT,$alias); - + return zeroBS_canUseAlias( ZBS_TYPE_CONTACT, $alias ); } - #} Get specific alias if exists -function zeroBS_getCustomerAlias($cID=-1,$alias=''){ - - return zeroBS_getObjAlias(ZBS_TYPE_CONTACT,$cID,$alias); +function zeroBS_getCustomerAlias( $cID = -1, $alias = '' ) { + return zeroBS_getObjAlias( ZBS_TYPE_CONTACT, $cID, $alias ); } #} Get specific alias if exists -function zeroBS_getCustomerAliasByID($cID=-1,$aliasID=-1){ - - return zeroBS_getAliasByID(ZBS_TYPE_CONTACT,$cID,$aliasID); +function zeroBS_getCustomerAliasByID( $cID = -1, $aliasID = -1 ) { + return zeroBS_getAliasByID( ZBS_TYPE_CONTACT, $cID, $aliasID ); } #} Get All Aliases against a contact. -function zeroBS_getCustomerAliases($cID=-1){ - - return zeroBS_getObjAliases(ZBS_TYPE_CONTACT,$cID); +function zeroBS_getCustomerAliases( $cID = -1 ) { + return zeroBS_getObjAliases( ZBS_TYPE_CONTACT, $cID ); } #} add Aliases to a contact. -function zeroBS_addCustomerAlias($cID=-1,$alias=''){ - - return zeroBS_addObjAlias(ZBS_TYPE_CONTACT,$cID,$alias); +function zeroBS_addCustomerAlias( $cID = -1, $alias = '' ) { + return zeroBS_addObjAlias( ZBS_TYPE_CONTACT, $cID, $alias ); } #} remove Alias from an contact -function zeroBS_removeCustomerAlias($cID=-1,$alias=''){ - - return zeroBS_removeObjAlias(ZBS_TYPE_CONTACT,$cID,$alias); +function zeroBS_removeCustomerAlias( $cID = -1, $alias = '' ) { + return zeroBS_removeObjAlias( ZBS_TYPE_CONTACT, $cID, $alias ); } #} remove Alias from a contact. -function zeroBS_removeCustomerAliasByID($cID=-1,$aliasID=-1){ - - return zeroBS_removeObjAliasByID(ZBS_TYPE_CONTACT,$cID,$aliasID); +function zeroBS_removeCustomerAliasByID( $cID = -1, $aliasID = -1 ) { + return zeroBS_removeObjAliasByID( ZBS_TYPE_CONTACT, $cID, $aliasID ); } - - -/* ====================================================== +/* +====================================================== / Contact -> aliases - ====================================================== */ +====================================================== */ +function zeroBSCRM_getLog( $lID = -1 ) { -function zeroBSCRM_getLog($lID=-1){ - - if ($lID !== -1){ + if ( $lID !== -1 ) { global $zbs; - return $zbs->DAL->logs->getLog(array( - 'id' => $lID, - 'incMeta' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + return $zbs->DAL->logs->getLog( + array( + 'id' => $lID, + 'incMeta' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); - } + } return false; } -function zeroBSCRM_getContactLogs($customerID=-1,$withFullDetails=false,$perPage=100,$page=0,$searchPhrase='',$argsOverride=false){ +function zeroBSCRM_getContactLogs( $customerID = -1, $withFullDetails = false, $perPage = 100, $page = 0, $searchPhrase = '', $argsOverride = false ) { if ( ! empty( $customerID ) && $customerID !== -1 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - global $zbs; - return $zbs->DAL->logs->getLogsForObj(array( + global $zbs; + return $zbs->DAL->logs->getLogsForObj( + array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $customerID, + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $customerID, - 'searchPhrase' => $searchPhrase, + 'searchPhrase' => $searchPhrase, - 'incMeta' => $withFullDetails, + 'incMeta' => $withFullDetails, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => $page, - 'perPage' => $perPage, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => $page, + 'perPage' => $perPage, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - )); + ) + ); - } - return array(); + } + return array(); } -function zeroBSCRM_getAllContactLogs($withFullDetails=false,$perPage=100,$page=0,$searchPhrase='',$argsOverride=false){ - +function zeroBSCRM_getAllContactLogs( $withFullDetails = false, $perPage = 100, $page = 0, $searchPhrase = '', $argsOverride = false ) { + global $zbs; - return $zbs->DAL->logs->getLogsForANYObj(array( + return $zbs->DAL->logs->getLogsForANYObj( + array( - 'objtype' => ZBS_TYPE_CONTACT, + 'objtype' => ZBS_TYPE_CONTACT, - 'searchPhrase' => $searchPhrase, + 'searchPhrase' => $searchPhrase, - 'incMeta' => $withFullDetails, + 'incMeta' => $withFullDetails, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => $page, - 'perPage' => $perPage, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => $page, + 'perPage' => $perPage, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - )); + ) + ); } -function zeroBSCRM_getCompanyLogs($companyID=false,$withFullDetails=false,$perPage=100,$page=0,$searchPhrase='',$argsOverride=false){ - - // DAL 3+ :) - if (!empty($companyID)){ - global $zbs; +function zeroBSCRM_getCompanyLogs( $companyID = false, $withFullDetails = false, $perPage = 100, $page = 0, $searchPhrase = '', $argsOverride = false ) { - return $zbs->DAL->logs->getLogsForObj(array( + // DAL 3+ :) + if ( ! empty( $companyID ) ) { + global $zbs; - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $companyID, + return $zbs->DAL->logs->getLogsForObj( + array( - 'searchPhrase' => $searchPhrase, + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $companyID, - 'incMeta' => $withFullDetails, + 'searchPhrase' => $searchPhrase, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => $page, - 'perPage' => $perPage, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + 'incMeta' => $withFullDetails, - )); - - } - return array(); + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => $page, + 'perPage' => $perPage, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); + } + return array(); } -function zeroBSCRM_getObjCreationLog($objID=-1,$objType=ZBS_TYPE_CONTACT){ +function zeroBSCRM_getObjCreationLog( $objID = -1, $objType = ZBS_TYPE_CONTACT ) { if ( ! empty( $objID ) && $objID !== -1 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - global $zbs; - return $zbs->DAL->logs->getLogsForObj( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - array( + global $zbs; + return $zbs->DAL->logs->getLogsForObj( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + array( - 'objtype' => $objType, - 'objid' => $objID, + 'objtype' => $objType, + 'objid' => $objID, - 'notetype' => 'Created', + 'notetype' => 'Created', - 'incMeta' => true, + 'incMeta' => true, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'ASC', - 'page' => 0, - 'perPage' => 1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'ASC', + 'page' => 0, + 'perPage' => 1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - ) - ); + ) + ); - } + } } -function zeroBSCRM_getMostRecentContactLog($objID=false,$withFullDetails=false,$restrictToTypes=false){ +function zeroBSCRM_getMostRecentContactLog( $objID = false, $withFullDetails = false, $restrictToTypes = false ) { - if (!empty($objID)){ + if ( ! empty( $objID ) ) { - global $zbs; + global $zbs; - return $zbs->DAL->logs->getLogsForObj(array( + return $zbs->DAL->logs->getLogsForObj( + array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $objID, + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $objID, - 'notetypes' => $restrictToTypes, + 'notetypes' => $restrictToTypes, - 'incMeta' => $withFullDetails, + 'incMeta' => $withFullDetails, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - )); + ) + ); - } + } } -function zeroBSCRM_getMostRecentCompanyLog($objID=false,$withFullDetails=false,$restrictToTypes=false){ +function zeroBSCRM_getMostRecentCompanyLog( $objID = false, $withFullDetails = false, $restrictToTypes = false ) { - if (!empty($objID)){ + if ( ! empty( $objID ) ) { - global $zbs; + global $zbs; - return $zbs->DAL->logs->getLogsForObj(array( + return $zbs->DAL->logs->getLogsForObj( + array( - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $objID, + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $objID, - 'notetypes' => $restrictToTypes, + 'notetypes' => $restrictToTypes, - 'incMeta' => $withFullDetails, + 'incMeta' => $withFullDetails, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - )); + ) + ); - } + } } - -function zeroBS_searchLogs($querystring){ +function zeroBS_searchLogs( $querystring ) { global $zbs; - return $zbs->DAL->logs->getLogsForANYObj(array( + return $zbs->DAL->logs->getLogsForANYObj( + array( 'searchPhrase' => $querystring, - 'perPage' => 100, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) - )); + 'perPage' => 100, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } -function zeroBS_allLogs(){ +function zeroBS_allLogs() { global $zbs; - return $zbs->DAL->logs->getLogsForANYObj(array( - 'perPage' => 100, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) - )); + return $zbs->DAL->logs->getLogsForANYObj( + array( + 'perPage' => 100, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } - - - +/** + * Adds or updates a log entry. + * + * @param int $cID Contact ID. + * @param int $logID Log ID. + * @param int $logDate Log date timestamp. + * @param array $noteFields Note fields array. Expected keys: zbsNoteAgainstPostID, zbsNoteType, + * zbsNoteShortDesc, zbsNoteLongDesc. May also include 'meta_assoc_id' + * (e.g. campaign ID for 'email sent' logs) and 'meta_assoc_src' + * (e.g. 'mailcamp'). + * @param string $objType Object type — e.g. 'contact' or 'zerobs_customer'. + * @param int $owner Owner ID. + */ function zeroBS_addUpdateLog( + $cID = -1, + $logID = -1, + $logDate = -1, + $noteFields = array(), + $objType = '', + $owner = -1 +) { - $cID = -1, - $logID = -1, - $logDate = -1, - - /* - #} Process with metaboxes.php funcs, is easier :) - - $zbsNoteAgainstPostID - $zbsNoteType - $zbsNoteShortDesc - $zbsNoteLongDesc - - NOTE!: as of 31/05/17 WOODY started putting - 'meta_assoc_id' in these - e.g. if it's an 'email sent' log, this meta_assoc_id will be the CAMPAIGN id - 'meta_assoc_src' would then be mailcamp - - */ - - $noteFields = array(), - - $objType='', /* contact or 'zerobs_contact' */ - $owner = -1 - - ){ - - global $zbs; - + global $zbs; - // DAL3 all obj logs: if ($objType == 'zerobs_customer'){ - //zeroBSCRM_DEPRECATEDMSG('zeroBS_addUpdateLog has been replaced by zeroBS_addUpdateContactLog etc. or (better still) DAL2 calls direct'); - //return zeroBS_addUpdateContactLog($cID,$logID,$logDate,$noteFields,$owner); - // DAL3 NO CPT LOGS: - //} else - // fallback + // DAL3 all obj logs: if ($objType == 'zerobs_customer'){ + // zeroBSCRM_DEPRECATEDMSG('zeroBS_addUpdateLog has been replaced by zeroBS_addUpdateContactLog etc. or (better still) DAL2 calls direct'); + // return zeroBS_addUpdateContactLog($cID,$logID,$logDate,$noteFields,$owner); + // DAL3 NO CPT LOGS: + // } else + // fallback - // translate zerobs_customer to 1 - $typeID = $zbs->DAL->objTypeID($objType); + // translate zerobs_customer to 1 + $typeID = $zbs->DAL->objTypeID( $objType ); // got type? - if ($typeID !== -1){ - - // assume this'll work. (should do.) - return zeroBS_addUpdateObjLog($typeID,$cID,$logID,$logDate,$noteFields,$owner); - - } + if ( $typeID !== -1 ) { - // no TYPE - zeroBSCRM_DEPRECATEDMSG( 'zeroBS_addUpdateLog has been replaced by DAL3 logging. Please do not use, or at least pass an object type.' ); - return false; + // assume this'll work. (should do.) + return zeroBS_addUpdateObjLog( $typeID, $cID, $logID, $logDate, $noteFields, $owner ); + } + // no TYPE + zeroBSCRM_DEPRECATEDMSG( 'zeroBS_addUpdateLog has been replaced by DAL3 logging. Please do not use, or at least pass an object type.' ); + return false; } // really should just be calling direct at this point, or zeroBS_addUpdateObjLog at least function zeroBS_addUpdateContactLog( - $cID = -1, - $logID = -1, - $logDate = -1, - $noteFields = array(), - $owner = -1 - ){ - - // wrapper for this: - return zeroBS_addUpdateObjLog(ZBS_TYPE_CONTACT,$cID,$logID,$logDate,$noteFields,$owner); - + $cID = -1, + $logID = -1, + $logDate = -1, + $noteFields = array(), + $owner = -1 +) { + + // wrapper for this: + return zeroBS_addUpdateObjLog( ZBS_TYPE_CONTACT, $cID, $logID, $logDate, $noteFields, $owner ); } // generic add obj log function zeroBS_addUpdateObjLog( - $objTypeID = -1, - $objID = -1, - $logID = -1, - $logDate = -1, - $noteFields = array(), - $owner = -1 - ){ - - if ($objTypeID > 0){ - - $logType = ''; - $logShortDesc = ''; - $logLongDesc = ''; - $logMeta = -1; + $objTypeID = -1, + $objID = -1, + $logID = -1, + $logDate = -1, + $noteFields = array(), + $owner = -1 +) { + + if ( $objTypeID > 0 ) { + + $logType = ''; + $logShortDesc = ''; + $logLongDesc = ''; + $logMeta = -1; + $logCreated = -1; + $pinned = -1; + if ( isset( $noteFields['type'] ) ) { + $logType = zeroBSCRM_permifyLogType( $noteFields['type'] ); + } + if ( isset( $noteFields['shortdesc'] ) ) { + $logShortDesc = $noteFields['shortdesc']; + } + if ( isset( $noteFields['longdesc'] ) ) { + $logLongDesc = $noteFields['longdesc']; + } + if ( isset( $noteFields['meta'] ) ) { + $logMeta = $noteFields['meta']; + } + if ( isset( $noteFields['pinned'] ) ) { + $pinned = $noteFields['pinned']; + } + if ( $logDate !== -1 ) { + $logCreated = strtotime( $logDate ); + } else { $logCreated = -1; - $pinned = -1; - if (isset($noteFields['type'])) $logType = zeroBSCRM_permifyLogType($noteFields['type']); - if (isset($noteFields['shortdesc'])) $logShortDesc = $noteFields['shortdesc']; - if (isset($noteFields['longdesc'])) $logLongDesc = $noteFields['longdesc']; - if (isset($noteFields['meta'])) $logMeta = $noteFields['meta']; - if (isset($noteFields['pinned'])) $pinned = $noteFields['pinned']; - if ($logDate !== -1) { - $logCreated = strtotime($logDate); - } - else { - $logCreated = -1; - } + } - global $zbs; + global $zbs; - return $zbs->DAL->logs->addUpdateLog(array( + return $zbs->DAL->logs->addUpdateLog( + array( - 'id' => $logID, - 'owner' => $owner, + 'id' => $logID, + 'owner' => $owner, - // fields (directly) - 'data' => array( + // fields (directly) + 'data' => array( - 'objtype' => $objTypeID, - 'objid' => $objID, - 'type' => $logType, - 'shortdesc' => $logShortDesc, - 'longdesc' => $logLongDesc, + 'objtype' => $objTypeID, + 'objid' => $objID, + 'type' => $logType, + 'shortdesc' => $logShortDesc, + 'longdesc' => $logLongDesc, - 'meta' => $logMeta, - 'pinned' => $pinned, + 'meta' => $logMeta, + 'pinned' => $pinned, - 'created' => $logCreated - - ))); + 'created' => $logCreated, - } + ), + ) + ); - return false; + } + return false; } - - - // allows us to lazily 'hotswap' wp_set_post_terms in extensions (e.g. pre DAL2 it'll just fire wp_set_post_terms) // ... here it does DAL2 equiv // WH Note: if using old WP method (wp_set_post_terms) can pass tags or tagIDS - DB2 currently only accepts tagIDs - to add in // ... to get around this I've temp added $usingTagIDS=true flag // still used in bulk-tagger and groove-connect extensions as of 9 May 1923 -function zeroBSCRM_DAL2_set_post_terms($cID=-1,$tags=array(),$taxonomy='zerobscrm_customertag',$append=true,$usingTagIDS=true){ +function zeroBSCRM_DAL2_set_post_terms( $cID = -1, $tags = array(), $taxonomy = 'zerobscrm_customertag', $append = true, $usingTagIDS = true ) { zeroBSCRM_DEPRECATEDMSG( 'zeroBSCRM_DAL2_set_post_terms has been replaced by DAL3 tagging. Please do not use.' ); - + global $zbs; // if we have tooo.... - $possibleObjTypeID = $zbs->DAL->cptTaxonomyToObjID($taxonomy); + $possibleObjTypeID = $zbs->DAL->cptTaxonomyToObjID( $taxonomy ); - if ($possibleObjTypeID > 0){ + if ( $possibleObjTypeID > 0 ) { - $mode = 'replace'; if ($append) $mode = 'append'; + $mode = 'replace'; + if ( $append ) { + $mode = 'append'; + } - $fieldName = 'tagIDs'; if (!$usingTagIDS) $fieldName = 'tags'; + $fieldName = 'tagIDs'; + if ( ! $usingTagIDS ) { + $fieldName = 'tags'; + } - return $zbs->DAL->addUpdateObjectTags(array( - 'objid' => $cID, - 'objtype' => $possibleObjTypeID, - $fieldName => $tags, - 'mode' => $mode - )); + return $zbs->DAL->addUpdateObjectTags( + array( + 'objid' => $cID, + 'objtype' => $possibleObjTypeID, + $fieldName => $tags, + 'mode' => $mode, + ) + ); } return false; - } // allows us to lazily 'hotswap' wp_set_object_terms in extensions (e.g. pre DAL2 it'll just fire wp_set_object_terms) @@ -2434,54 +2503,67 @@ function zeroBSCRM_DAL2_set_post_terms($cID=-1,$tags=array(),$taxonomy='zerobscr // WH Note: if using old WP method (wp_set_object_terms) can pass tags or tagIDS - DB2 currently only accepts tagIDs - to add in // ... to get around this I've temp added $usingTagIDS=true flag // still used in several extensions as of 9 May 1923 -function zeroBSCRM_DAL2_set_object_terms($cID=-1,$tags=array(),$taxonomy='zerobscrm_customertag',$append=true,$usingTagIDS=true){ +function zeroBSCRM_DAL2_set_object_terms( $cID = -1, $tags = array(), $taxonomy = 'zerobscrm_customertag', $append = true, $usingTagIDS = true ) { zeroBSCRM_DEPRECATEDMSG( 'zeroBSCRM_DAL2_set_object_terms has been replaced by DAL3 tagging. Please do not use.' ); - + global $zbs; // if we have tooo.... - $possibleObjTypeID = $zbs->DAL->cptTaxonomyToObjID($taxonomy); + $possibleObjTypeID = $zbs->DAL->cptTaxonomyToObjID( $taxonomy ); - if ($possibleObjTypeID > 0){ + if ( $possibleObjTypeID > 0 ) { - $mode = 'replace'; if ($append) $mode = 'append'; + $mode = 'replace'; + if ( $append ) { + $mode = 'append'; + } - $fieldName = 'tagIDs'; if (!$usingTagIDS) $fieldName = 'tags'; + $fieldName = 'tagIDs'; + if ( ! $usingTagIDS ) { + $fieldName = 'tags'; + } - return $zbs->DAL->addUpdateObjectTags(array( - 'objid' => $cID, - 'objtype' => $possibleObjTypeID, - $fieldName => $tags, - 'mode' => $mode - )); + return $zbs->DAL->addUpdateObjectTags( + array( + 'objid' => $cID, + 'objtype' => $possibleObjTypeID, + $fieldName => $tags, + 'mode' => $mode, + ) + ); } return false; /* // we only switch out for customer tags, rest just go old way - if ($taxonomy == 'zerobscrm_customertag'){ + if ( $taxonomy == 'zerobscrm_customertag'){ global $zbs; - $mode = 'replace'; if ($append) $mode = 'append'; + $mode = 'replace'; + if ( $append ) { + $mode = 'append'; + } - $fieldName = 'tagIDs'; if (!$usingTagIDS) $fieldName = 'tags'; + $fieldName = 'tagIDs'; + if ( !$usingTagIDS ) { + $fieldName = 'tags'; + } return $zbs->DAL->addUpdateObjectTags(array( - 'objid' => $cID, - 'objtype' => ZBS_TYPE_CONTACT, - $fieldName => $tags, - 'mode' => $mode + 'objid' => $cID, + 'objtype' => ZBS_TYPE_CONTACT, + $fieldName => $tags, + 'mode' => $mode )); } else { //https://codex.wordpress.org/Function_Reference/wp_set_object_terms return wp_set_object_terms($cID,$tags,$taxonomy,$append); - - } */ + } */ } #} This takes an array source (can be $_POST) and builds out a meta field array for it.. @@ -2492,23 +2574,22 @@ function zeroBSCRM_DAL2_set_object_terms($cID=-1,$tags=array(),$taxonomy='zerobs #} 27/09/16: Can now also pass starting array, which lets you "override" fields present in $arraySource, without loosing originals not passed #} 12/04/18: Added prefix so as to be able to pass normal array e.g. fname (by passing empty fieldPrefix) #} 3.0: this was moved to generic zeroBS_buildObjArr :) -function zeroBS_buildContactMeta($arraySource=array(),$startingArray=array(),$fieldPrefix='zbsc_',$outputPrefix='',$removeEmpties=false,$autoGenAutonumbers=false){ +function zeroBS_buildContactMeta( $arraySource = array(), $startingArray = array(), $fieldPrefix = 'zbsc_', $outputPrefix = '', $removeEmpties = false, $autoGenAutonumbers = false ) { // moved to generic, just return that :) - return zeroBS_buildObjArr($arraySource,$startingArray,$fieldPrefix,$outputPrefix,$removeEmpties,ZBS_TYPE_CONTACT,$autoGenAutonumbers); + return zeroBS_buildObjArr( $arraySource, $startingArray, $fieldPrefix, $outputPrefix, $removeEmpties, ZBS_TYPE_CONTACT, $autoGenAutonumbers ); } -/* ====================================================== - / Unchanged DAL2->3 (Mostly customer/contact + log relatead) - ====================================================== */ +/* +====================================================== + / Unchanged DAL2->3 (Mostly customer/contact + log relatead) +====================================================== */ // ==================================================================================================================================== // ==================================================================================================================================== // ==================== / DAL 2.0 FUNCS =============================================================================================== // ==================================================================================================================================== // ==================================================================================================================================== - - // ==================================================================================================================================== // ==================================================================================================================================== @@ -2516,602 +2597,607 @@ function zeroBS_buildContactMeta($arraySource=array(),$startingArray=array(),$fi // ==================================================================================================================================== // ==================================================================================================================================== -/* ====================================================== - GENERIC helpers - ====================================================== */ - - #} This is a fill-in until we deprecate addUpdateTransaction etc. (3.5 or so) - #} it'll take a DAL1 obj (e.g. transaction with 'orderid') and produce a v3 translated field variant (e.g. orderid => ref (via 'dal1key' attr on obj model)) - #} param $objType = ZBS_TYPE_TRANSACTION - #} param $fieldPrefix = zbst_ if fields are prefixed with - function zeroBS_translateDAL1toDAL3Obj($arraySource=array(),$objType=-1,$fieldPrefix=''){ - - if ($objType > 0){ - - global $zbs; - - //$objectModel = $zbs->DAL->objModel($objType); - $objectLayer = $zbs->DAL->getObjectLayerByType($objType); +/* +====================================================== + GENERIC helpers +====================================================== */ - if (isset($objectLayer)){ + #} This is a fill-in until we deprecate addUpdateTransaction etc. (3.5 or so) + #} it'll take a DAL1 obj (e.g. transaction with 'orderid') and produce a v3 translated field variant (e.g. orderid => ref (via 'dal1key' attr on obj model)) + #} param $objType = ZBS_TYPE_TRANSACTION + #} param $fieldPrefix = zbst_ if fields are prefixed with +function zeroBS_translateDAL1toDAL3Obj( $arraySource = array(), $objType = -1, $fieldPrefix = '' ) { - $ret = array(); - $objTranslationMatrix = $objectLayer->getDAL1toDAL3ConversionMatrix(); - if (!is_array($objTranslationMatrix)) $objTranslationMatrix = array(); + if ( $objType > 0 ) { - foreach ($arraySource as $k => $v){ + global $zbs; - $kClean = $k; if (!empty($fieldPrefix)) $kClean = str_replace($fieldPrefix,'',$k); + // $objectModel = $zbs->DAL->objModel($objType); + $objectLayer = $zbs->DAL->getObjectLayerByType( $objType ); - if (isset($objTranslationMatrix[$kClean])){ + if ( isset( $objectLayer ) ) { - // is translatable - $ret[$fieldPrefix.$objTranslationMatrix[$kClean]] = $v; + $ret = array(); + $objTranslationMatrix = $objectLayer->getDAL1toDAL3ConversionMatrix(); + if ( ! is_array( $objTranslationMatrix ) ) { + $objTranslationMatrix = array(); + } - } else { + foreach ( $arraySource as $k => $v ) { - // isn't translatable - $ret[$k] = $v; + $kClean = $k; + if ( ! empty( $fieldPrefix ) ) { + $kClean = str_replace( $fieldPrefix, '', $k ); + } - } + if ( isset( $objTranslationMatrix[ $kClean ] ) ) { + // is translatable + $ret[ $fieldPrefix . $objTranslationMatrix[ $kClean ] ] = $v; - } + } else { - } // / has object layer + // isn't translatable + $ret[ $k ] = $v; - } // / has objtype + } + } + } // / has object layer - return $ret; + } // / has objtype - } + return $ret; +} #} This takes an array source (can be $_POST) and builds out a meta field array for it.. - #} ... this is a generalised postarray->objarray creator, built from zeroBS_buildContactMeta, - #} ... now produces all "meta" (objarrays) for all objs. Centralised to keep DRY - #} 13/03/19: Added $autoGenAutonumbers - if TRUE, empty/non-passed autonumber custom fields will assume fresh + autogen (useful for PORTAL/SYNC generated) - function zeroBS_buildObjArr($arraySource=array(),$startingArray=array(),$fieldPrefix='zbsc_',$outputPrefix='',$removeEmpties=false,$objType=ZBS_TYPE_CONTACT,$autoGenAutonumbers=false){ - - #} def - $retArray = array(); - - #} if passed... - if (isset($startingArray) && is_array($startingArray)) $retArray = $startingArray; + #} ... this is a generalised postarray->objarray creator, built from zeroBS_buildContactMeta, + #} ... now produces all "meta" (objarrays) for all objs. Centralised to keep DRY + #} 13/03/19: Added $autoGenAutonumbers - if TRUE, empty/non-passed autonumber custom fields will assume fresh + autogen (useful for PORTAL/SYNC generated) +function zeroBS_buildObjArr( $arraySource = array(), $startingArray = array(), $fieldPrefix = 'zbsc_', $outputPrefix = '', $removeEmpties = false, $objType = ZBS_TYPE_CONTACT, $autoGenAutonumbers = false ) { - #} go + #} def + $retArray = array(); - // req. - global $zbs; - - // DAL3 notes: (See #globalfieldobjsdal3 in fields.php) - // .. ultimately we default to using the $fields globals, then fallback to the objmodels - // introduced in DAL3 objs. This allows coverage of both, for now - // v3.0 RC+ this can be refactored :) - // Note: To make RC1 I also added in translation, which is perhaps a step toward refactoring this: - - // Some RC1 field translations (requires dal1key against changed obj model fields) - $arraySource = zeroBS_translateDAL1toDAL3Obj($arraySource,$objType,$fieldPrefix); + #} if passed... + if ( isset( $startingArray ) && is_array( $startingArray ) ) { + $retArray = $startingArray; + } - // retrieve global var name - $globFieldVarName = $zbs->DAL->objFieldVarName($objType); + #} go - // nope. (for events in DAL3) - // ... potentially can turn this off for all non DAL3? may be redundant inside next {} - if ($objType !== ZBS_TYPE_TASK && $objType !== ZBS_TYPE_QUOTETEMPLATE && isset($GLOBALS[$globFieldVarName])){ + // req. + global $zbs; - $i=0; + // DAL3 notes: (See #globalfieldobjsdal3 in fields.php) + // .. ultimately we default to using the $fields globals, then fallback to the objmodels + // introduced in DAL3 objs. This allows coverage of both, for now + // v3.0 RC+ this can be refactored :) + // Note: To make RC1 I also added in translation, which is perhaps a step toward refactoring this: - foreach ($GLOBALS[$globFieldVarName] as $fK => $fV){ + // Some RC1 field translations (requires dal1key against changed obj model fields) + $arraySource = zeroBS_translateDAL1toDAL3Obj( $arraySource, $objType, $fieldPrefix ); - $i++; + // retrieve global var name + $globFieldVarName = $zbs->DAL->objFieldVarName( $objType ); - // if it's not an autonumber (which generates new on blank passes), set it to empty - // ... or if it has $autoGenAutonumbers = true, - if ( - ($fV[0] !== 'autonumber' && !isset($retArray[$outputPrefix.$fK])) - || - $autoGenAutonumbers - ) - $retArray[$outputPrefix.$fK] = ''; + // nope. (for events in DAL3) + // ... potentially can turn this off for all non DAL3? may be redundant inside next {} + if ( $objType !== ZBS_TYPE_TASK && $objType !== ZBS_TYPE_QUOTETEMPLATE && isset( $GLOBALS[ $globFieldVarName ] ) ) { - // two EXCEPTIONS: - // 1) custom field type checkbox, because it adds -0 -1 etc. to options, so this wont fire, - // 2) Autonumbers which are blank to start with get caught beneath - // ... see below for checkbox catch - if (isset($arraySource[$fieldPrefix.$fK])) { + $i = 0; - switch ($fV[0]){ + foreach ( $GLOBALS[ $globFieldVarName ] as $fK => $fV ) { + ++$i; - case 'tel': + // if it's not an autonumber (which generates new on blank passes), set it to empty + // ... or if it has $autoGenAutonumbers = true, + if ( + ( $fV[0] !== 'autonumber' && ! isset( $retArray[ $outputPrefix . $fK ] ) ) + || + $autoGenAutonumbers + ) { + $retArray[ $outputPrefix . $fK ] = ''; + } - // validate tel? Should be an user option, allow validation. - $retArray[$outputPrefix.$fK] = sanitize_text_field($arraySource[$fieldPrefix.$fK]); - //$retArray[$outputPrefix.$fK] = preg_replace("/[^0-9 .+\-()]/", '', $retArray[$outputPrefix.$fK]); - break; + // two EXCEPTIONS: + // 1) custom field type checkbox, because it adds -0 -1 etc. to options, so this wont fire, + // 2) Autonumbers which are blank to start with get caught beneath + // ... see below for checkbox catch + if ( isset( $arraySource[ $fieldPrefix . $fK ] ) ) { - case 'price': - case 'numberfloat': + switch ( $fV[0] ) { - $retArray[$outputPrefix.$fK] = sanitize_text_field($arraySource[$fieldPrefix.$fK]); - $retArray[$outputPrefix.$fK] = preg_replace('@[^0-9\.]+@i', '-', $retArray[$outputPrefix.$fK]); - $retArray[$outputPrefix.$fK] = floatval($retArray[$outputPrefix.$fK]); - break; + case 'tel': + // validate tel? Should be an user option, allow validation. + $retArray[ $outputPrefix . $fK ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); + // $retArray[$outputPrefix.$fK] = preg_replace("/[^0-9 .+\-()]/", '', $retArray[$outputPrefix.$fK]); + break; - case 'numberint': + case 'price': + case 'numberfloat': + $retArray[ $outputPrefix . $fK ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); + $retArray[ $outputPrefix . $fK ] = preg_replace( '@[^0-9\.]+@i', '-', $retArray[ $outputPrefix . $fK ] ); + $retArray[ $outputPrefix . $fK ] = floatval( $retArray[ $outputPrefix . $fK ] ); + break; - $retArray[$outputPrefix.$fK] = sanitize_text_field($arraySource[$fieldPrefix.$fK]); - $retArray[$outputPrefix.$fK] = preg_replace('@[^0-9]+@i', '-', $retArray[$outputPrefix.$fK]); - $retArray[$outputPrefix.$fK] = intval($retArray[$outputPrefix.$fK]); - break; + case 'numberint': + $retArray[ $outputPrefix . $fK ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); + $retArray[ $outputPrefix . $fK ] = preg_replace( '@[^0-9]+@i', '-', $retArray[ $outputPrefix . $fK ] ); + $retArray[ $outputPrefix . $fK ] = intval( $retArray[ $outputPrefix . $fK ] ); + break; case 'textarea': - // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $retArray[ $outputPrefix . $fK ] = sanitize_textarea_field( $arraySource[ $fieldPrefix . $fK ] ); + // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $retArray[ $outputPrefix . $fK ] = sanitize_textarea_field( $arraySource[ $fieldPrefix . $fK ] ); break; case 'date': - $safe_text = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $safe_text = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $retArray[ $outputPrefix . $fK ] = jpcrm_date_str_to_uts( $safe_text, '!Y-m-d', true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $retArray[ $outputPrefix . $fK ] = jpcrm_date_str_to_uts( $safe_text, '!Y-m-d', true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase break; - case 'datetime': - - $retArray[$outputPrefix.$fK] = sanitize_text_field($arraySource[$fieldPrefix.$fK]); - - // translate datetime to UTS (without time) - // ... by default from DAL3.0 - $retArray[$outputPrefix.$fK] = zeroBSCRM_locale_dateToUTS($retArray[$outputPrefix.$fK],true); - - break; - - case 'radio': - case 'select': - - // just get value, easy. - $retArray[$outputPrefix.$fK] = sanitize_text_field($arraySource[$fieldPrefix.$fK]); - - break; - - // autonumber dealt with below this if {} - case 'autonumber': - - // pass it along :) - $retArray[$outputPrefix.$fK] = sanitize_text_field($arraySource[$fieldPrefix.$fK]); - - break; - - // checkbox dealt with below this if {} - - default: - - $retArray[$outputPrefix.$fK] = sanitize_text_field($arraySource[$fieldPrefix.$fK]); - - break; + case 'datetime': + $retArray[ $outputPrefix . $fK ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); + // translate datetime to UTS (without time) + // ... by default from DAL3.0 + $retArray[ $outputPrefix . $fK ] = zeroBSCRM_locale_dateToUTS( $retArray[ $outputPrefix . $fK ], true ); + break; - } // / switch type + case 'radio': + case 'select': + // just get value, easy. + $retArray[ $outputPrefix . $fK ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); + break; - } // / if isset (simple) $arraySource[$fieldPrefix.$fK] + // autonumber dealt with below this if {} + case 'autonumber': + // pass it along :) + $retArray[ $outputPrefix . $fK ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); + break; - // catch checkboxes - if ($fV[0] == 'checkbox'){ + // checkbox dealt with below this if {} - // there are several ways that checkbox (multiselect) inputs may be passed, depending on source - // because this function catches from: - // - edit page post - // - client portal profile page - // - Gravity forms/extension calls - // - API - // ... to name a few, it's sensible that we try and catch the variants (low risk/cost here) - $checkboxArr = array(); + default: + $retArray[ $outputPrefix . $fK ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); - // Checkbox input: Iterative - // This cycles through `checkboxkey-$i` (up to 64 options) and includes if they're set - // This is used by our edit pages, client portal profile page etc. - for ($checkboxI = 0; $checkboxI < 64; $checkboxI++){ + break; - if (isset($arraySource[$fieldPrefix.$fK.'-'.$checkboxI])) { + } // / switch type - // retrieve - $checkboxArr[] = $arraySource[$fieldPrefix.$fK.'-'.$checkboxI]; + } // / if isset (simple) $arraySource[$fieldPrefix.$fK] - } + // catch checkboxes + if ( $fV[0] == 'checkbox' ) { - } + // there are several ways that checkbox (multiselect) inputs may be passed, depending on source + // because this function catches from: + // - edit page post + // - client portal profile page + // - Gravity forms/extension calls + // - API + // ... to name a few, it's sensible that we try and catch the variants (low risk/cost here) + $checkboxArr = array(); - // Checkbox input: CSV - // This can be exploded - // This is used by gravity forms, when multiple 1 word options are checked (and probably elsewhere) - if (isset($arraySource[$fieldPrefix.$fK]) && is_string($arraySource[$fieldPrefix.$fK])) { + // Checkbox input: Iterative + // This cycles through `checkboxkey-$i` (up to 64 options) and includes if they're set + // This is used by our edit pages, client portal profile page etc. + for ( $checkboxI = 0; $checkboxI < 64; $checkboxI++ ) { - // one option or multi? - if (strpos($arraySource[$fieldPrefix.$fK], ',')) - $checkboxArr = explode(',', $arraySource[$fieldPrefix.$fK]); - else - $checkboxArr = array($arraySource[$fieldPrefix.$fK]); + if ( isset( $arraySource[ $fieldPrefix . $fK . '-' . $checkboxI ] ) ) { - } + // retrieve + $checkboxArr[] = $arraySource[ $fieldPrefix . $fK . '-' . $checkboxI ]; - // Checkbox input: Array - // This can be straight passed - // This is used by gravity forms, when at least one option with multiple words are checked (and probably elsewhere, is good to support pass through) - if (isset($arraySource[$fieldPrefix.$fK]) && is_array($arraySource[$fieldPrefix.$fK])) { - $checkboxArr = $arraySource[$fieldPrefix.$fK]; - } + } + } + // Checkbox input: CSV + // This can be exploded + // This is used by gravity forms, when multiple 1 word options are checked (and probably elsewhere) + if ( isset( $arraySource[ $fieldPrefix . $fK ] ) && is_string( $arraySource[ $fieldPrefix . $fK ] ) ) { - if (is_array($checkboxArr)){ + // one option or multi? + if ( strpos( $arraySource[ $fieldPrefix . $fK ], ',' ) ) { + $checkboxArr = explode( ',', $arraySource[ $fieldPrefix . $fK ] ); + } else { + $checkboxArr = array( $arraySource[ $fieldPrefix . $fK ] ); + } + } - // sanitize - $checkboxArr = array_map( 'sanitize_text_field', $checkboxArr ); + // Checkbox input: Array + // This can be straight passed + // This is used by gravity forms, when at least one option with multiple words are checked (and probably elsewhere, is good to support pass through) + if ( isset( $arraySource[ $fieldPrefix . $fK ] ) && is_array( $arraySource[ $fieldPrefix . $fK ] ) ) { + $checkboxArr = $arraySource[ $fieldPrefix . $fK ]; + } - // csv em - $retArray[$outputPrefix.$fK] = implode(',',$checkboxArr); + if ( is_array( $checkboxArr ) ) { - } else { + // sanitize + $checkboxArr = array_map( 'sanitize_text_field', $checkboxArr ); - // none selected, set blank - $retArray[$outputPrefix.$fK] = ''; + // csv em + $retArray[ $outputPrefix . $fK ] = implode( ',', $checkboxArr ); - } + } else { + // none selected, set blank + $retArray[ $outputPrefix . $fK ] = ''; + } + } // / if checkbox - } // / if checkbox + // if autonumber + if ( $fV[0] == 'autonumber' ) { - // if autonumber - if ($fV[0] == 'autonumber'){ + // this is a generated field. + // if was previously set, sticks with that, if not set, will generate new, based on custom field rule + // NOTE!!!! if this is NOT SET in customerMeta, it WILL NOT be updated + // ... this is because when passing incomplete update records (e.g. not passing autonumber) + // ... it doesn't need a new AUTONUMBER + // ... so if you want a fresh autonumber, you need to pass with $startingArray[] EMPTY value set - // this is a generated field. - // if was previously set, sticks with that, if not set, will generate new, based on custom field rule - // NOTE!!!! if this is NOT SET in customerMeta, it WILL NOT be updated - // ... this is because when passing incomplete update records (e.g. not passing autonumber) - // ... it doesn't need a new AUTONUMBER - // ... so if you want a fresh autonumber, you need to pass with $startingArray[] EMPTY value set - - // if not yet set - if (isset($retArray[$outputPrefix.$fK]) && empty($retArray[$outputPrefix.$fK])){ + // if not yet set + if ( isset( $retArray[ $outputPrefix . $fK ] ) && empty( $retArray[ $outputPrefix . $fK ] ) ) { - // retrieve based on custom field rule - $autono = ''; + // retrieve based on custom field rule + $autono = ''; - // retrieve rule - $formatExample = ''; - if (isset($fV[2])) { - $formatExample = $fV[2]; - } + // retrieve rule + $formatExample = ''; + if ( isset( $fV[2] ) ) { + $formatExample = $fV[2]; + } if ( ! empty( $formatExample ) && str_contains( $formatExample, '#' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // has a rule at least - $formatParts = explode('#', $formatExample); + // has a rule at least + $formatParts = explode( '#', $formatExample ); - // build + // build - // prefix - if (!empty($formatParts[0])) $autono .= zeroBSCRM_customFields_parseAutoNumberStr($formatParts[0]); + // prefix + if ( ! empty( $formatParts[0] ) ) { + $autono .= zeroBSCRM_customFields_parseAutoNumberStr( $formatParts[0] ); + } - // number - $no = zeroBSCRM_customFields_getAutoNumber($objType,$fK); - if ($no > 0 && $no !== false) $autono .= $no; - - // suffix - if (!empty($formatParts[2])) $autono .= zeroBSCRM_customFields_parseAutoNumberStr($formatParts[2]); + // number + $no = zeroBSCRM_customFields_getAutoNumber( $objType, $fK ); + if ( $no > 0 && $no !== false ) { + $autono .= $no; + } - // if legit, add - if ($no > 0 && $no !== false) $retArray[$outputPrefix.$fK] = $autono; - } - } + // suffix + if ( ! empty( $formatParts[2] ) ) { + $autono .= zeroBSCRM_customFields_parseAutoNumberStr( $formatParts[2] ); + } - } // / if autonumber + // if legit, add + if ( $no > 0 && $no !== false ) { + $retArray[ $outputPrefix . $fK ] = $autono; + } + } + } + } // / if autonumber + } // / foreach field - } // / foreach field + } // / if global-based-fill-out - } // / if global-based-fill-out + $replaceMap = array( + 'secaddr1' => 'secaddr_addr1', + 'secaddr2' => 'secaddr_addr2', + 'seccity' => 'secaddr_city', + 'seccounty' => 'secaddr_county', + 'seccountry' => 'secaddr_country', + 'secpostcode' => 'secaddr_postcode', + ); - $replaceMap = array( - 'secaddr1' => 'secaddr_addr1', - 'secaddr2' => 'secaddr_addr2', - 'seccity' => 'secaddr_city', - 'seccounty' => 'secaddr_county', - 'seccountry' => 'secaddr_country', - 'secpostcode' => 'secaddr_postcode' - ); + foreach ( $replaceMap as $d2key => $d1key ) { + if ( isset( $retArray[ $outputPrefix . $d1key ] ) ) { + $retArray[ $outputPrefix . $d2key ] = $retArray[ $outputPrefix . $d1key ]; + unset( $retArray[ $outputPrefix . $d1key ] ); + } + } - foreach ($replaceMap as $d2key => $d1key) - if (isset($retArray[$outputPrefix.$d1key])){ - $retArray[$outputPrefix.$d2key] = $retArray[$outputPrefix.$d1key]; - unset($retArray[$outputPrefix.$d1key]); - } + // can also pass some extras :) /social + // for co + contact + if ( $objType == ZBS_TYPE_CONTACT || $objType == ZBS_TYPE_COMPANY ) { - // can also pass some extras :) /social - // for co + contact - if ($objType == ZBS_TYPE_CONTACT || $objType == ZBS_TYPE_COMPANY){ + $extras = array( 'tw', 'fb', 'li' ); + foreach ( $extras as $fK ) { - $extras = array('tw','fb','li'); - foreach ($extras as $fK){ + if ( ! isset( $retArray[ $outputPrefix . $fK ] ) ) { + $retArray[ $outputPrefix . $fK ] = ''; + } - if (!isset($retArray[$outputPrefix.$fK])) $retArray[$outputPrefix.$fK] = ''; + if ( isset( $arraySource[ $fieldPrefix . $fK ] ) ) { - if (isset($arraySource[$fieldPrefix.$fK])) { + $retArray[ $outputPrefix . $fK ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fK ] ); - $retArray[$outputPrefix.$fK] = sanitize_text_field($arraySource[$fieldPrefix.$fK]); + } + } + } - } + // ... Further, from DAL3+ we now have proper object models, which probably should replace "fields" + // above, but for now, churning through both, as sensitively as possible. - } + // get an obj model, if set + $potentialModel = $zbs->DAL->objModel( $objType ); - } + // will be objlayer model if set + if ( is_array( $potentialModel ) ) { - // ... Further, from DAL3+ we now have proper object models, which probably should replace "fields" - // above, but for now, churning through both, as sensitively as possible. + // cycle through each field + set, if not already set by the above. + foreach ( $potentialModel as $fieldKey => $fieldDetail ) { - // get an obj model, if set - $potentialModel = $zbs->DAL->objModel($objType); + // there's a few we ignore :) + if ( in_array( $fieldKey, array( 'ID', 'zbs_site', 'zbs_team' ) ) ) { + continue; + } - // will be objlayer model if set - if (is_array($potentialModel)){ + // if not already set + if ( ! isset( $retArray[ $outputPrefix . $fieldKey ] ) ) { - // cycle through each field + set, if not already set by the above. - foreach ($potentialModel as $fieldKey => $fieldDetail){ + // retrieve based on type + switch ( $fieldDetail['format'] ) { - // there's a few we ignore :) - if (in_array($fieldKey, array('ID','zbs_site','zbs_team'))) continue; + case 'str': + case 'curr': // for now, process curr as str. (probs needs to just validate IS CURR) + if ( isset( $arraySource[ $fieldPrefix . $fieldKey ] ) ) { + $retArray[ $outputPrefix . $fieldKey ] = zeroBSCRM_textProcess( $arraySource[ $fieldPrefix . $fieldKey ] ); + } + break; - // if not already set - if (!isset($retArray[$outputPrefix.$fieldKey])){ + case 'int': + if ( isset( $arraySource[ $fieldPrefix . $fieldKey ] ) ) { - // retrieve based on type - switch ($fieldDetail['format']){ - - case 'str': - case 'curr': // for now, process curr as str. (probs needs to just validate IS CURR) - if (isset($arraySource[$fieldPrefix.$fieldKey])) $retArray[$outputPrefix.$fieldKey] = zeroBSCRM_textProcess($arraySource[$fieldPrefix.$fieldKey]); - break; + $retArray[ $outputPrefix . $fieldKey ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fieldKey ] ); + $retArray[ $outputPrefix . $fieldKey ] = preg_replace( '@[^0-9]+@i', '-', $retArray[ $outputPrefix . $fieldKey ] ); + $retArray[ $outputPrefix . $fieldKey ] = intval( $retArray[ $outputPrefix . $fieldKey ] ); - case 'int': - if (isset($arraySource[$fieldPrefix.$fieldKey])) { + } + break; + case 'uts': + if ( isset( $arraySource[ $fieldPrefix . $fieldKey ] ) ) { - $retArray[$outputPrefix.$fieldKey] = sanitize_text_field($arraySource[$fieldPrefix.$fieldKey]); - $retArray[$outputPrefix.$fieldKey] = preg_replace('@[^0-9]+@i', '-', $retArray[$outputPrefix.$fieldKey]); - $retArray[$outputPrefix.$fieldKey] = intval($retArray[$outputPrefix.$fieldKey]); + $retArray[ $outputPrefix . $fieldKey ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fieldKey ] ); - } - break; - case 'uts': - if (isset($arraySource[$fieldPrefix.$fieldKey])) { - - $retArray[$outputPrefix.$fieldKey] = sanitize_text_field($arraySource[$fieldPrefix.$fieldKey]); - - // in case of UTS dates, the $_POST likely passed may be in date format - // ... if so, take the model default + translate (if set) - if (isset($fieldDetail['autoconvert']) && $fieldDetail['autoconvert'] == 'date'){ + // in case of UTS dates, the $_POST likely passed may be in date format + // ... if so, take the model default + translate (if set) + if ( isset( $fieldDetail['autoconvert'] ) && $fieldDetail['autoconvert'] == 'date' ) { - // translate "01/12/2018" to UTS (without time) - $retArray[$outputPrefix.$fieldKey] = zeroBSCRM_locale_dateToUTS($retArray[$outputPrefix.$fieldKey],false); + // translate "01/12/2018" to UTS (without time) + $retArray[ $outputPrefix . $fieldKey ] = zeroBSCRM_locale_dateToUTS( $retArray[ $outputPrefix . $fieldKey ], false ); - } - if (isset($fieldDetail['autoconvert']) && $fieldDetail['autoconvert'] == 'datetime'){ + } + if ( isset( $fieldDetail['autoconvert'] ) && $fieldDetail['autoconvert'] == 'datetime' ) { - // translate datetime to UTS (with time) - $retArray[$outputPrefix.$fieldKey] = zeroBSCRM_locale_dateToUTS($retArray[$outputPrefix.$fieldKey],true); + // translate datetime to UTS (with time) + $retArray[ $outputPrefix . $fieldKey ] = zeroBSCRM_locale_dateToUTS( $retArray[ $outputPrefix . $fieldKey ], true ); - } + } - $retArray[$outputPrefix.$fieldKey] = preg_replace('@[^0-9]+@i', '-', $retArray[$outputPrefix.$fieldKey]); - $retArray[$outputPrefix.$fieldKey] = intval($retArray[$outputPrefix.$fieldKey]); + $retArray[ $outputPrefix . $fieldKey ] = preg_replace( '@[^0-9]+@i', '-', $retArray[ $outputPrefix . $fieldKey ] ); + $retArray[ $outputPrefix . $fieldKey ] = intval( $retArray[ $outputPrefix . $fieldKey ] ); - } - break; + } + break; - case 'bool': - if (isset($arraySource[$fieldPrefix.$fieldKey])) { - $retArray[$outputPrefix.$fieldKey] = sanitize_text_field($arraySource[$fieldPrefix.$fieldKey]); - $retArray[$outputPrefix.$fieldKey] = preg_replace('@[^0-9]+@i', '-', $retArray[$outputPrefix.$fieldKey]); - $retArray[$outputPrefix.$fieldKey] = boolval($retArray[$outputPrefix.$fieldKey]); - } - break; + case 'bool': + if ( isset( $arraySource[ $fieldPrefix . $fieldKey ] ) ) { + $retArray[ $outputPrefix . $fieldKey ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fieldKey ] ); + $retArray[ $outputPrefix . $fieldKey ] = preg_replace( '@[^0-9]+@i', '-', $retArray[ $outputPrefix . $fieldKey ] ); + $retArray[ $outputPrefix . $fieldKey ] = boolval( $retArray[ $outputPrefix . $fieldKey ] ); + } + break; - case 'decimal': - if (isset($arraySource[$fieldPrefix.$fieldKey])){ - $retArray[$outputPrefix.$fieldKey] = sanitize_text_field($arraySource[$fieldPrefix.$fieldKey]); - $retArray[$outputPrefix.$fieldKey] = preg_replace('@[^0-9]+@i', '-', $retArray[$outputPrefix.$fieldKey]); - $retArray[$outputPrefix.$fieldKey] = floatval($retArray[$outputPrefix.$fieldKey]); - } - break; + case 'decimal': + if ( isset( $arraySource[ $fieldPrefix . $fieldKey ] ) ) { + $retArray[ $outputPrefix . $fieldKey ] = sanitize_text_field( $arraySource[ $fieldPrefix . $fieldKey ] ); + $retArray[ $outputPrefix . $fieldKey ] = preg_replace( '@[^0-9]+@i', '-', $retArray[ $outputPrefix . $fieldKey ] ); + $retArray[ $outputPrefix . $fieldKey ] = floatval( $retArray[ $outputPrefix . $fieldKey ] ); + } + break; - default: // basically str. - if (isset($arraySource[$fieldPrefix.$fieldKey])) $retArray[$outputPrefix.$fieldKey] = zeroBSCRM_textProcess($arraySource[$fieldPrefix.$fieldKey]); - break; + default: // basically str. + if ( isset( $arraySource[ $fieldPrefix . $fieldKey ] ) ) { + $retArray[ $outputPrefix . $fieldKey ] = zeroBSCRM_textProcess( $arraySource[ $fieldPrefix . $fieldKey ] ); + } + break; + } // / format switch - } // / format switch + } // / not isset - } // / not isset + } // / foreach - } // / foreach + } // / if has model - } // / if has model + // $removeEmpties + if ( $removeEmpties ) { - // $removeEmpties - if ($removeEmpties){ + $ret = array(); + foreach ( $retArray as $k => $v ) { - $ret = array(); - foreach ($retArray as $k => $v){ - - $intV = (int)$v; + $intV = (int) $v; - if (!is_array($v) && !empty($v) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1){ - $ret[$k] = $v; + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { + $ret[ $k ] = $v; } + } - } - - $retArray = $ret; + $retArray = $ret; - } + } - return $retArray; - } + return $retArray; +} // generally used for list view reformatting - cleans a contact array into simple format // here it takes an array of contacts, and (currently) returns 1 contact simplified // This may make more sense in the contact DAL obj layer? // >> this has a company variant too, in this file. - function zeroBSCRM_getSimplyFormattedContact($contacts=array(),$requireOwner=false){ +function zeroBSCRM_getSimplyFormattedContact( $contacts = array(), $requireOwner = false ) { - $return = false; + $return = false; - // DAL3 + has potential for multi-links, so here we just grab first if there - if (isset($contacts) && is_array($contacts) && count($contacts) > 0){ + // DAL3 + has potential for multi-links, so here we just grab first if there + if ( isset( $contacts ) && is_array( $contacts ) && count( $contacts ) > 0 ) { - // first only for now... - $contact = $contacts[0]; + // first only for now... + $contact = $contacts[0]; - // w adapted so same func can be used (generic) js side - // works with zeroBSCRMJS_listView_generic_customer - // provides a simplified ver of customer obj (4 data transit efficiency/exposure) - $email = ''; - if (isset($contact['email']) && !empty($contact['email'])) $email = $contact['email']; - global $zbs; - $return = array( - 'id' => $contact['id'], - 'avatar' => $zbs->DAL->contacts->getContactAvatar( $contact['id'] ), // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - 'fullname' => zeroBS_customerName( '', $contact, false, false ), - 'email' => $email, - ); - - if ($requireOwner) $return['owner'] = zeroBS_getOwner($contact['id'],true,'zerobs_customer'); - - } + // w adapted so same func can be used (generic) js side + // works with zeroBSCRMJS_listView_generic_customer + // provides a simplified ver of customer obj (4 data transit efficiency/exposure) + $email = ''; + if ( isset( $contact['email'] ) && ! empty( $contact['email'] ) ) { + $email = $contact['email']; + } + global $zbs; + $return = array( + 'id' => $contact['id'], + 'avatar' => $zbs->DAL->contacts->getContactAvatar( $contact['id'] ), // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + 'fullname' => zeroBS_customerName( '', $contact, false, false ), + 'email' => $email, + ); - return $return; + if ( $requireOwner ) { + $return['owner'] = zeroBS_getOwner( $contact['id'], true, 'zerobs_customer' ); + } + } - } + return $return; +} -/* ====================================================== - / GENERIC helpers - ====================================================== */ +/* +====================================================== + / GENERIC helpers +====================================================== */ -/* ====================================================== - Company helpers - ====================================================== */ +/* +====================================================== + Company helpers +====================================================== */ #} Get the COUNT of companies. - function zeroBS_companyCount($status=false){ - - global $zbs; return $zbs->DAL->companies->getCompanyCount(array( - 'withStatus'=> $status, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); +function zeroBS_companyCount( $status = false ) { - } + global $zbs; + return $zbs->DAL->companies->getCompanyCount( + array( + 'withStatus' => $status, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); +} - // another func which should be skipped 3.0+, just do direct call :) - function zeroBS_getCompany($coID=-1,$withObjs=false){ + // another func which should be skipped 3.0+, just do direct call :) +function zeroBS_getCompany( $coID = -1, $withObjs = false ) { - if ($coID !== -1){ + if ( $coID !== -1 ) { - global $zbs; + global $zbs; - #} Super rough. Not sure where we use this, but shouldn't. - return $zbs->DAL->companies->getCompany($coID,array( - 'withQuotes' => $withObjs, - 'withInvoices' => $withObjs, + #} Super rough. Not sure where we use this, but shouldn't. + return $zbs->DAL->companies->getCompany( + $coID, + array( + 'withQuotes' => $withObjs, + 'withInvoices' => $withObjs, 'withTransactions' => $withObjs, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY)) - ); - - } - - return false; + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); } + return false; +} + #} Wrapper func for "company" type customers // note: $inCountry returns with address 1 or 2 in country (added for logReporter for Miguel (custom extension WH)) // note: $withStatus returns with specific status (added for logReporter for Miguel (custom extension WH)) #} Adapted for 3.0+, note deprecated really, should be using DAL->companies->getCompanies directly - function zeroBS_getCompanies( - - $withFullDetails=false, - $perPage=10, - $page=0, - $searchPhrase='', - $argsOverride=false, - $withInvoices=false, - $withQuotes=false, - $withTransactions=false, - $inCountry=false, - $ownedByID=false, - $withStatus=false, - $inArr=false - - - ){ - - - // $withFullDetails = irrelevant with new DB2 (always returns) - // $argsOverride CAN NO LONGER WORK :) - if ($argsOverride !== false) zeroBSCRM_DEPRECATEDMSG('Use of $argsOverride in zeroBS_getCompanies is no longer relevant (DAL3.0)'); +function zeroBS_getCompanies( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $searchPhrase = '', + $argsOverride = false, + $withInvoices = false, + $withQuotes = false, + $withTransactions = false, + $inCountry = false, + $ownedByID = false, + $withStatus = false, + $inArr = false +) { - global $zbs; - - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; - - // make ARGS - $args = array( - - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArr, - 'inCountry' => $inCountry, - 'hasStatus' => $withStatus, - 'ownedBy' => $ownedByID, + // $withFullDetails = irrelevant with new DB2 (always returns) + // $argsOverride CAN NO LONGER WORK :) + if ( $argsOverride !== false ) { + zeroBSCRM_DEPRECATEDMSG( 'Use of $argsOverride in zeroBS_getCompanies is no longer relevant (DAL3.0)' ); + } - 'withCustomFields' => true, - 'withQuotes' => $withQuotes, - 'withInvoices' => $withInvoices, - 'withTransactions' => $withTransactions, - 'withLogs' => false, - 'withLastLog' => false, - 'withTags' => false,//$withTags, - 'withOwner' => false, + global $zbs; - //'sortByField' => $sortByField, - //'sortOrder' => $sortOrder, - 'page' => $actualPage, - 'perPage' => $perPage, + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; + } - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY) + // make ARGS + $args = array( + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArr, + 'inCountry' => $inCountry, + 'hasStatus' => $withStatus, + 'ownedBy' => $ownedByID, - ); + 'withCustomFields' => true, + 'withQuotes' => $withQuotes, + 'withInvoices' => $withInvoices, + 'withTransactions' => $withTransactions, + 'withLogs' => false, + 'withLastLog' => false, + 'withTags' => false, // $withTags, + 'withOwner' => false, - // here ignore owners = true the default, because we're not really forcing ownership anywhere overall, - // when we do, we should change this/make it check - if ($ownedByID !== false && is_int($ownedByID) && $ownedByID > 0) { + // 'sortByField' => $sortByField, + // 'sortOrder' => $sortOrder, + 'page' => $actualPage, + 'perPage' => $perPage, - $args['ignoreowner'] = false; + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), - } + ); - return $zbs->DAL->companies->getCompanies($args); + // here ignore owners = true the default, because we're not really forcing ownership anywhere overall, + // when we do, we should change this/make it check + if ( $ownedByID !== false && is_int( $ownedByID ) && $ownedByID > 0 ) { + $args['ignoreowner'] = false; } + return $zbs->DAL->companies->getCompanies( $args ); +} + // returns email for a company - function zeroBS_companyEmail($companyID='',$companyArr=false){ - - global $zbs; return $zbs->DAL->companies->getCompanyEmail($companyID); +function zeroBS_companyEmail( $companyID = '', $companyArr = false ) { - } + global $zbs; + return $zbs->DAL->companies->getCompanyEmail( $companyID ); +} /** * Retrieves the company ID based on its name. @@ -3128,200 +3214,201 @@ function zeroBS_getCompanyIDWithName( $company_name = '' ) { } #} ExternalID is name in this case :) - function zeroBS_getCompanyIDWithExternalSource($externalSource='',$externalID=''){ - - global $zbs; - - #} No empties, no random externalSources :) - if (!empty($externalSource) && !empty($externalID) && array_key_exists($externalSource,$zbs->external_sources)){ - - #} If here, is legit. - $approvedExternalSource = $externalSource; +function zeroBS_getCompanyIDWithExternalSource( $externalSource = '', $externalID = '' ) { - global $zbs; + global $zbs; - return $zbs->DAL->companies->getCompany(-1,array( - 'externalSource' => $approvedExternalSource, - 'externalSourceUID' => $externalID, - 'onlyID' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY) - )); + #} No empties, no random externalSources :) + if ( ! empty( $externalSource ) && ! empty( $externalID ) && array_key_exists( $externalSource, $zbs->external_sources ) ) { - } + #} If here, is legit. + $approvedExternalSource = $externalSource; + global $zbs; - return false; + return $zbs->DAL->companies->getCompany( + -1, + array( + 'externalSource' => $approvedExternalSource, + 'externalSourceUID' => $externalID, + 'onlyID' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); } - + return false; +} // This should probably be deprecated and just called directly. // for now just translating - function zeroBS_getCompaniesForTypeahead($searchQueryStr=''){ - - /* - //gets them all, from a brutal SQL - global $wpdb; - - if (!empty($searchQueryStr)){ - - // param query - $sql = "SELECT ID as id, post_title as name, post_date as created FROM $wpdb->posts WHERE post_type = 'zerobs_company' AND post_status = 'publish' AND post_title LIKE %s"; - $q = $wpdb->prepare($sql,'%'.$searchQueryStr.'%'); - $results = $wpdb->get_results($q, ARRAY_A); - - } else { +function zeroBS_getCompaniesForTypeahead( $searchQueryStr = '' ) { - // straight query - $sql = "SELECT ID as id, post_title as name, post_date as created FROM $wpdb->posts WHERE post_type = 'zerobs_company' AND post_status = 'publish'"; - $results = $wpdb->get_results($sql, ARRAY_A); - } + /* + //gets them all, from a brutal SQL + global $wpdb; - return $results; - */ - global $zbs; + if ( !empty( $searchQueryStr)){ - return $zbs->DAL->companies->getCompanies(array( - 'searchPhrase' => $searchQueryStr, - 'simplified' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY) - )); + // param query + $sql = "SELECT ID as id, post_title as name, post_date as created FROM $wpdb->posts WHERE post_type = 'zerobs_company' AND post_status = 'publish' AND post_title LIKE %s"; + $q = $wpdb->prepare($sql,'%'.$searchQueryStr.'%'); + $results = $wpdb->get_results($q, ARRAY_A); - } + } else { + // straight query + $sql = "SELECT ID as id, post_title as name, post_date as created FROM $wpdb->posts WHERE post_type = 'zerobs_company' AND post_status = 'publish'"; + $results = $wpdb->get_results($sql, ARRAY_A); + } - function zeroBS_getCompanyIDWithEmail($custEmail=''){ + return $results; + */ + global $zbs; - if (!empty($custEmail)){ + return $zbs->DAL->companies->getCompanies( + array( + 'searchPhrase' => $searchQueryStr, + 'simplified' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); +} - global $zbs; - return $zbs->DAL->companies->getCompany(-1,array( - 'email' => $custEmail, - 'onlyID' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY) - )); +function zeroBS_getCompanyIDWithEmail( $custEmail = '' ) { - } + if ( ! empty( $custEmail ) ) { - return false; + global $zbs; + return $zbs->DAL->companies->getCompany( + -1, + array( + 'email' => $custEmail, + 'onlyID' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); } + return false; +} + #} Add or Update a Company - ideally use $zbs->DAL->companies->addUpdateCompany() rather than this wrapper, in proper code now :) +function zeroBS_addUpdateCompany( + $coID = -1, + $coFields = array(), + $externalSource = '', + $externalID = '', + $companyDate = '', + $fallBackLog = false, + $extraMeta = false, + $automatorPassthrough = false, + $owner = -1, + $metaBuilderPrefix = 'zbsc_' +) { + + #} Basics - /--needs status + #} 27/09/16 - WH - Removed need for zeroBS_addUpdateCustomer to have a "status" passed with customer (defaults to lead for now if not present) + if ( isset( $coFields ) && count( $coFields ) > 0 ) { #} && isset( $coFields['zbsc_status']) + global $zbs; - #} Add or Update a Company - ideally use $zbs->DAL->companies->addUpdateCompany() rather than this wrapper, in proper code now :) - function zeroBS_addUpdateCompany( - - $coID = -1, - - $coFields = array(), - $externalSource='', - $externalID='', - $companyDate='', - - $fallBackLog = false, - $extraMeta = false, - $automatorPassthrough = false, - - $owner = -1, - $metaBuilderPrefix = 'zbsc_' - - ){ - - - #} Basics - /--needs status - #} 27/09/16 - WH - Removed need for zeroBS_addUpdateCustomer to have a "status" passed with customer (defaults to lead for now if not present) - if (isset($coFields) && count($coFields) > 0){ #} && isset($coFields['zbsc_status']) - - global $zbs; - - #} New flag - $newCompany = false; $existingMeta = array(); - - - if ($coID > 0){ - - #} Build "existing meta" to pass, (so we only update fields pushed here) - $existingMeta = $zbs->DAL->companies->getCompany($coID,array()); + #} New flag + $newCompany = false; + $existingMeta = array(); - #} need to check the dates here. If a date is passed which is BEFORE the current "created" date then overwrite the date with the new date. If a date is passed which is AFTER the current "created" date, then do not update the date.. - #} date changed - created is only in the wp_posts table in DB v1.0 - $originalDate = time(); - if (isset($existingMeta) && is_array($existingMeta) && isset($existingMeta['created']) && !empty($existingMeta['created'])) $originalDate = $existingMeta['created']; + if ( $coID > 0 ) { - if (!empty($companyDate) && $companyDate != ''){ + #} Build "existing meta" to pass, (so we only update fields pushed here) + $existingMeta = $zbs->DAL->companies->getCompany( $coID, array() ); - #} DATE PASSED TO THE FUNCTION - $companyDateTimeStamp = strtotime($companyDate); - #} ORIGINAL POST CREATION DATE - // no need, db2 = UTS $originalDateTimeStamp = strtotime($originalDate); - $originalDateTimeStamp = $originalDate; + #} need to check the dates here. If a date is passed which is BEFORE the current "created" date then overwrite the date with the new date. If a date is passed which is AFTER the current "created" date, then do not update the date.. + #} date changed - created is only in the wp_posts table in DB v1.0 + $originalDate = time(); + if ( isset( $existingMeta ) && is_array( $existingMeta ) && isset( $existingMeta['created'] ) && ! empty( $existingMeta['created'] ) ) { + $originalDate = $existingMeta['created']; + } - #} Compare, if $companyDateTimeStamp < then update with passed date - if($companyDateTimeStamp < $originalDateTimeStamp){ + if ( ! empty( $companyDate ) && $companyDate != '' ) { - // straight in there :) - $zbs->DAL->companies->addUpdateCompany(array( - 'id' => $coID, - 'limitedFields' =>array( - array('key'=>'zbsco_created','val'=>$companyDateTimeStamp,'type'=>'%d') - ))); - } - } + #} DATE PASSED TO THE FUNCTION + $companyDateTimeStamp = strtotime( $companyDate ); + #} ORIGINAL POST CREATION DATE + // no need, db2 = UTS $originalDateTimeStamp = strtotime($originalDate); + $originalDateTimeStamp = $originalDate; - // WH changed 20/05/18 - // 20/05/18 - Previously this would reload the EXISTING database data - // THEN 'override' any passed fields - // THEN save that down - // ... this was required when we used old meta objs. (pre db2) - // ... so if we're now DAL2, we can do away with that and simply pass what's to be updated and mode do_not_update_blanks - $existingMeta = array(); + #} Compare, if $companyDateTimeStamp < then update with passed date + if ( $companyDateTimeStamp < $originalDateTimeStamp ) { - } else { + // straight in there :) + $zbs->DAL->companies->addUpdateCompany( + array( + 'id' => $coID, + 'limitedFields' => array( + array( + 'key' => 'zbsco_created', + 'val' => $companyDateTimeStamp, + 'type' => '%d', + ), + ), + ) + ); + } + } - #} Set flag - $newCompany = true; + // WH changed 20/05/18 + // 20/05/18 - Previously this would reload the EXISTING database data + // THEN 'override' any passed fields + // THEN save that down + // ... this was required when we used old meta objs. (pre db2) + // ... so if we're now DAL2, we can do away with that and simply pass what's to be updated and mode do_not_update_blanks + $existingMeta = array(); - if (!empty($companyDate)){ + } else { - #} DATE PASSED TO THE FUNCTION - $companyDateTimeStamp = strtotime($companyDate); - if ($companyDateTimeStamp > 0) $existingMeta = array('created' => $companyDateTimeStamp); + #} Set flag + $newCompany = true; - } + if ( ! empty( $companyDate ) ) { + #} DATE PASSED TO THE FUNCTION + $companyDateTimeStamp = strtotime( $companyDate ); + if ( $companyDateTimeStamp > 0 ) { + $existingMeta = array( 'created' => $companyDateTimeStamp ); } + } + } - #} Build using centralised func below, passing any existing meta (updates not overwrites) - $zbsCompanyMeta = zeroBS_buildCompanyMeta($coFields,$existingMeta,$metaBuilderPrefix,'',true); + #} Build using centralised func below, passing any existing meta (updates not overwrites) + $zbsCompanyMeta = zeroBS_buildCompanyMeta( $coFields, $existingMeta, $metaBuilderPrefix, '', true ); - $we_have_tags = false; //set to false.. duh.. + $we_have_tags = false; // set to false.. duh.. - # TAG company (if exists) - clean etc here too - if (!empty($coFields['tags'])){ + # TAG company (if exists) - clean etc here too + if ( ! empty( $coFields['tags'] ) ) { - $tags = $coFields['tags']; + $tags = $coFields['tags']; - #} Santize tags - if(is_array($tags) && count($tags) > 0){ - $company_tags = filter_var_array($tags,FILTER_UNSAFE_RAW); - // Formerly this used FILTER_SANITIZE_STRING, which is now deprecated as it was fairly broken. This is basically equivalent. - // @todo Replace this with something more correct. - foreach ( $company_tags as $k => $v ) { - $company_tags[$k] = strtr( - strip_tags( $v ), - array( - "\0" => '', - '"' => '"', - "'" => ''', - "<" => '', - ) - ); - } - $we_have_tags = true; - } + #} Santize tags + if ( is_array( $tags ) && count( $tags ) > 0 ) { + $company_tags = filter_var_array( $tags, FILTER_UNSAFE_RAW ); + // Formerly this used FILTER_SANITIZE_STRING, which is now deprecated as it was fairly broken. This is basically equivalent. + // @todo Replace this with something more correct. + foreach ( $company_tags as $k => $v ) { + $company_tags[ $k ] = strtr( + strip_tags( $v ), + array( + "\0" => '', + '"' => '"', + "'" => ''', + '<' => '', + ) + ); + } + $we_have_tags = true; + } if ( $we_have_tags ) { @@ -3358,481 +3445,511 @@ function zeroBS_addUpdateCompany( } } + #} Add external source/externalid + #} No empties, no random externalSources :) + $extSourceArr = -1; + $approvedExternalSource = ''; #} As this is passed to automator :) + if ( ! empty( $externalSource ) && ! empty( $externalID ) && array_key_exists( $externalSource, $zbs->external_sources ) ) { - #} Add external source/externalid - #} No empties, no random externalSources :) - $extSourceArr = -1; $approvedExternalSource = ''; #} As this is passed to automator :) - if (!empty($externalSource) && !empty($externalID) && array_key_exists($externalSource,$zbs->external_sources)){ - - #} If here, is legit. - $approvedExternalSource = $externalSource; - - #} Add/Update record flag - // 2.4+ Migrated away from this method to new update_post_meta($postID, 'zbs_customer_ext_'.$approvedExternalSource, $externalID); - // 2.52+ Moved to new DAL method :) - - $extSourceArr = array( - 'source' => $approvedExternalSource, - 'uid' => $externalID - ); + #} If here, is legit. + $approvedExternalSource = $externalSource; - // add/update - // DB2, this is just used below :)zeroBS_updateExternalSource($postID,$extSourceArr); - $zbsCompanyMeta['externalSources'] = array($extSourceArr); + #} Add/Update record flag + // 2.4+ Migrated away from this method to new update_post_meta($postID, 'zbs_customer_ext_'.$approvedExternalSource, $externalID); + // 2.52+ Moved to new DAL method :) - } #} Otherwise will just be a random customer no ext source + $extSourceArr = array( + 'source' => $approvedExternalSource, + 'uid' => $externalID, + ); - #} Got owner? - if ($owner !== -1) $zbsCompanyMeta['owner'] = $owner; + // add/update + // DB2, this is just used below :)zeroBS_updateExternalSource($postID,$extSourceArr); + $zbsCompanyMeta['externalSources'] = array( $extSourceArr ); - #} Update record (All IA is now fired intrinsicly ) - return $zbs->DAL->companies->addUpdateCompany(array( - 'id' => $coID, - 'data' => $zbsCompanyMeta, - 'extraMeta' => $extraMeta, - 'automatorPassthrough' => $automatorPassthrough, - 'fallBackLog' => $fallBackLog - )); + } #} Otherwise will just be a random customer no ext source + #} Got owner? + if ( $owner !== -1 ) { + $zbsCompanyMeta['owner'] = $owner; + } - } // if fields + #} Update record (All IA is now fired intrinsicly ) + return $zbs->DAL->companies->addUpdateCompany( + array( + 'id' => $coID, + 'data' => $zbsCompanyMeta, + 'extraMeta' => $extraMeta, + 'automatorPassthrough' => $automatorPassthrough, + 'fallBackLog' => $fallBackLog, + ) + ); - return false; + } // if fields - } + return false; +} // v3.0+ this uses the generic zeroBS_buildObjArr, and accepts full args as per contact meta DAL2: - function zeroBS_buildCompanyMeta($arraySource=array(),$startingArray=array(),$fieldPrefix='zbsco_',$outputPrefix='',$removeEmpties=false,$autoGenAutonumbers=false){ +function zeroBS_buildCompanyMeta( $arraySource = array(), $startingArray = array(), $fieldPrefix = 'zbsco_', $outputPrefix = '', $removeEmpties = false, $autoGenAutonumbers = false ) { - return zeroBS_buildObjArr($arraySource,$startingArray,$fieldPrefix,$outputPrefix,$removeEmpties,ZBS_TYPE_COMPANY,$autoGenAutonumbers); - - } + return zeroBS_buildObjArr( $arraySource, $startingArray, $fieldPrefix, $outputPrefix, $removeEmpties, ZBS_TYPE_COMPANY, $autoGenAutonumbers ); +} /* Centralised delete company func, including sub-element removal */ - function zeroBS_deleteCompany($id=-1,$saveOrphans=true){ - - if (!empty($id)){ +function zeroBS_deleteCompany( $id = -1, $saveOrphans = true ) { - global $zbs; + if ( ! empty( $id ) ) { - return $zbs->DAL->companies->deleteCompany(array('id'=>$id,'saveOrphans'=>$saveOrphans)); + global $zbs; - } + return $zbs->DAL->companies->deleteCompany( + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); - return false; } + return false; +} + // adapted company name builder to use proper DAL3 func - function zeroBS_companyName($companyID='',$companyArr=array(),$incFirstLineAddr=true,$incID=true){ - - global $zbs; return $zbs->DAL->companies->getCompanyNameEtc($companyID,$companyArr,array( - 'incFirstLineAddr' => $incFirstLineAddr, - 'incID' => $incID - )); - - } +function zeroBS_companyName( $companyID = '', $companyArr = array(), $incFirstLineAddr = true, $incID = true ) { + + global $zbs; + return $zbs->DAL->companies->getCompanyNameEtc( + $companyID, + $companyArr, + array( + 'incFirstLineAddr' => $incFirstLineAddr, + 'incID' => $incID, + ) + ); +} // adapted company name builder to use proper DAL3 func - function zeroBS_companyAddr($companyID='',$companyArr=array(),$addrFormat = 'short',$delimiter= ', '){ - - global $zbs; return $zbs->DAL->companies->getCompanyAddress($companyID,$companyArr,array( - 'addrFormat' => $addrFormat, - 'delimiter' => $delimiter - )); +function zeroBS_companyAddr( $companyID = '', $companyArr = array(), $addrFormat = 'short', $delimiter = ', ' ) { - } + global $zbs; + return $zbs->DAL->companies->getCompanyAddress( + $companyID, + $companyArr, + array( + 'addrFormat' => $addrFormat, + 'delimiter' => $delimiter, + ) + ); +} // adapted company name builder to use proper DAL3 func - function zeroBS_companySecondAddr($companyID='',$companyArr=array(),$addrFormat = 'short',$delimiter= ', '){ - - global $zbs; return $zbs->DAL->companies->getCompany2ndAddress($companyID,$companyArr,array( - 'addrFormat' => $addrFormat, - 'delimiter' => $delimiter - )); +function zeroBS_companySecondAddr( $companyID = '', $companyArr = array(), $addrFormat = 'short', $delimiter = ', ' ) { - } + global $zbs; + return $zbs->DAL->companies->getCompany2ndAddress( + $companyID, + $companyArr, + array( + 'addrFormat' => $addrFormat, + 'delimiter' => $delimiter, + ) + ); +} // sets tags, in future just use direct DAL func plz - function zeroBSCRM_setCompanyTags($coID=-1,$tags=array(),$tagIDs=array(),$mode='replace'){ +function zeroBSCRM_setCompanyTags( $coID = -1, $tags = array(), $tagIDs = array(), $mode = 'replace' ) { - if ($coID > 0){ + if ( $coID > 0 ) { - $args = array( + $args = array( - 'id' => $coID, + 'id' => $coID, - // EITHER of the following: - //'tagIDs' => -1, - //'tags' => -1, + // EITHER of the following: + // 'tagIDs' => -1, + // 'tags' => -1, - 'mode' => $mode - ); + 'mode' => $mode, + ); - // got tags? - if (is_array($tags) && count($tags) > 0) - $args['tags'] = $tags; - else if (is_array($tagIDs) && count($tagIDs) > 0) - $args['tagIDs'] = $tagIDs; - else - return false; + // got tags? + if ( is_array( $tags ) && count( $tags ) > 0 ) { + $args['tags'] = $tags; + } elseif ( is_array( $tagIDs ) && count( $tagIDs ) > 0 ) { + $args['tagIDs'] = $tagIDs; + } else { + return false; + } - global $zbs; - return $zbs->DAL->companies->addUpdateCompanyTags($args); + global $zbs; + return $zbs->DAL->companies->addUpdateCompanyTags( $args ); + } - } + return false; +} - return false; - - } - // gets tags, in future just use direct DAL func plz - function zeroBSCRM_getCompanyTagsByID($coID=-1,$justIDs=false){ - - global $zbs; - $tags = $zbs->DAL->companies->getCompanyTags($coID); +function zeroBSCRM_getCompanyTagsByID( $coID = -1, $justIDs = false ) { - // lazy here, but shouldn't use these old funcs anyhow! - if ($justIDs){ + global $zbs; + $tags = $zbs->DAL->companies->getCompanyTags( $coID ); - $ret = array(); - if (is_array($tags)) foreach ($tags as $t) $ret[] = $t['id']; - return $ret; + // lazy here, but shouldn't use these old funcs anyhow! + if ( $justIDs ) { + $ret = array(); + if ( is_array( $tags ) ) { + foreach ( $tags as $t ) { + $ret[] = $t['id']; + } } - - return $tags; + return $ret; } + return $tags; +} + // generally used for list view reformatting - cleans a company array into simple format // here it takes an array of contacts, and (currently) returns 1 company simplified // This may make more sense in the company DAL obj layer? // >> this has a contact variant too, in this file. - function zeroBSCRM_getSimplyFormattedCompany($companies=array(),$requireOwner=false){ - - $return = false; - - // DAL3 + has potential for multi-links, so here we just grab first if there - if (isset($companies) && is_array($companies) && count($companies) > 0){ - - // first only for now... - $company = $companies[0]; +function zeroBSCRM_getSimplyFormattedCompany( $companies = array(), $requireOwner = false ) { - // w adapted so same func can be used (generic) js side - // works with zeroBSCRMJS_listView_generic_customer - // provides a simplified ver of customer obj (4 data transit efficiency/exposure) - $email = ''; - if (isset($company['email']) && !empty($company['email'])) $email = $company['email']; - $return = array( + $return = false; - // company only has name, id, email currently - 'id' => $company['id'], - 'fullname' => $company['name'], - 'email' => $email + // DAL3 + has potential for multi-links, so here we just grab first if there + if ( isset( $companies ) && is_array( $companies ) && count( $companies ) > 0 ) { - ); - if ($requireOwner) $return['owner'] = zeroBS_getOwner($company['id'],true,'zerobs_company'); + // first only for now... + $company = $companies[0]; - } - - return $return; + // w adapted so same func can be used (generic) js side + // works with zeroBSCRMJS_listView_generic_customer + // provides a simplified ver of customer obj (4 data transit efficiency/exposure) + $email = ''; + if ( isset( $company['email'] ) && ! empty( $company['email'] ) ) { + $email = $company['email']; + } + $return = array( - } -/* ====================================================== - / Company helpers - ====================================================== */ + // company only has name, id, email currently + 'id' => $company['id'], + 'fullname' => $company['name'], + 'email' => $email, -/* ====================================================== - Quote helpers - ====================================================== */ + ); + if ( $requireOwner ) { + $return['owner'] = zeroBS_getOwner( $company['id'], true, 'zerobs_company' ); + } + } - # Quote Status (from list view) - // WH note - not sure why we're building HTML here, allowing for now. - // if returnAsInt - will return -1 for not published, -2 for not accepted, or 14int timestamp for accepted - function zeroBS_getQuoteStatus( $item=false, $returnAsInt=false ) { + return $return; +} +/* +====================================================== + / Company helpers +====================================================== */ - #} marked accepted? - $accepted = false; - if (is_array($item) && isset($item['accepted'])) $accepted = $item['accepted']; +/* +====================================================== + Quote helpers +====================================================== */ - # HERE TODO: - # if acceptedArr = output "accepted xyz" - # else if !templated outut "not yet published" - # else if templated output "not yet accepted" + # Quote Status (from list view) + // WH note - not sure why we're building HTML here, allowing for now. + // if returnAsInt - will return -1 for not published, -2 for not accepted, or 14int timestamp for accepted +function zeroBS_getQuoteStatus( $item = false, $returnAsInt = false ) { - if ($accepted > 0){ + #} marked accepted? + $accepted = false; + if ( is_array( $item ) && isset( $item['accepted'] ) ) { + $accepted = $item['accepted']; + } - if ($returnAsInt) return $accepted; + # HERE TODO: + # if acceptedArr = output "accepted xyz" + # else if !templated outut "not yet published" + # else if templated output "not yet accepted" - $td = ''.__('Accepted',"zero-bs-crm").' ' . date(zeroBSCRM_getDateFormat(),$accepted) . ''; + if ( $accepted > 0 ) { - } else { - - #} get extra deets - $zbsTemplated = $item['template']; - if (!empty($zbsTemplated)) { - - if ($returnAsInt) return -2; + if ( $returnAsInt ) { + return $accepted; + } - #} is published - $td = ''.__('Created, not yet accepted',"zero-bs-crm").''; + $td = '' . __( 'Accepted', 'zero-bs-crm' ) . ' ' . date( zeroBSCRM_getDateFormat(), $accepted ) . ''; - } else { + } else { - if ($returnAsInt) return -1; + #} get extra deets + $zbsTemplated = $item['template']; + if ( ! empty( $zbsTemplated ) ) { - #} not yet published - $td = ''.__('Not yet published',"zero-bs-crm").''; + if ( $returnAsInt ) { + return -2; + } - } + #} is published + $td = '' . __( 'Created, not yet accepted', 'zero-bs-crm' ) . ''; + } else { - } + if ( $returnAsInt ) { + return -1; + } + #} not yet published + $td = '' . __( 'Not yet published', 'zero-bs-crm' ) . ''; - return $td; - } + } + } - // Get next available sequential quote ID - function zeroBSCRM_getNextQuoteID(){ + return $td; +} - #} Retrieves option, and returns, is dumb for now. - // DAL1+2: return (int)get_option('quoteindx',$defaultStartingQuoteID)+1; + // Get next available sequential quote ID +function zeroBSCRM_getNextQuoteID() { - // DAL3: - $potential = (int)zeroBSCRM_getSetting('quoteindx',true); - if ($potential > 0) - return $potential+1; - else - return zeroBSCRM_getQuoteOffset()+1; + #} Retrieves option, and returns, is dumb for now. + // DAL1+2: return (int)get_option('quoteindx',$defaultStartingQuoteID)+1; + // DAL3: + $potential = (int) zeroBSCRM_getSetting( 'quoteindx', true ); + if ( $potential > 0 ) { + return $potential + 1; + } else { + return zeroBSCRM_getQuoteOffset() + 1; } +} // set the current max used quoteid - function zeroBSCRM_setMaxQuoteID($newMax=0){ +function zeroBSCRM_setMaxQuoteID( $newMax = 0 ) { - $existingMax = zeroBSCRM_getNextQuoteID(); + $existingMax = zeroBSCRM_getNextQuoteID(); - if ($newMax >= $existingMax){ + if ( $newMax >= $existingMax ) { - // DAL3: - global $zbs; - return $zbs->settings->update('quoteindx',$newMax); - - } + // DAL3: + global $zbs; + return $zbs->settings->update( 'quoteindx', $newMax ); - return false; } + return false; +} #} Minified get offset func - function zeroBSCRM_getQuoteOffset(){ +function zeroBSCRM_getQuoteOffset() { - global $zbs; - $offset = (int)$zbs->settings->get('quoteoffset'); - - if (empty($offset) || $offset < 0) $offset = 0; - - return $offset; + global $zbs; + $offset = (int) $zbs->settings->get( 'quoteoffset' ); + if ( empty( $offset ) || $offset < 0 ) { + $offset = 0; } - #} Old get func, use proper form if writing fresh code - // used to return array('id','meta','customerid','quotebuilder') - // ... so any existing use may be broken (have mass replaced in core at this point) - // ... use direct ->getQuotes in future anyhow. - // (which is diff format! any use of zeroBS_getQuote is now borked. - couldn't find any though + did proper search.) - function zeroBS_getQuote($qID=-1,$withQuoteBuilderData=false){ + return $offset; +} - if ($qID !== -1){ +#} Old get func, use proper form if writing fresh code +// used to return array('id','meta','customerid','quotebuilder') +// ... so any existing use may be broken (have mass replaced in core at this point) +// ... use direct ->getQuotes in future anyhow. +// (which is diff format! any use of zeroBS_getQuote is now borked. - couldn't find any though + did proper search.) +function zeroBS_getQuote( $qID = -1, $withQuoteBuilderData = false ) { - global $zbs; + if ( $qID !== -1 ) { - #} Super rough. Not sure where we use this, but shouldn't. - return $zbs->DAL->quotes->getQuote($qID,array( - 'withLineItems' => $withQuoteBuilderData, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE)) - ); + global $zbs; - } + #} Super rough. Not sure where we use this, but shouldn't. + return $zbs->DAL->quotes->getQuote( + $qID, + array( + 'withLineItems' => $withQuoteBuilderData, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), + ) + ); - return false; } + return false; +} + #} Marks a quote as "accepted" and saves as much related data as poss on accepter // again, use DAL to do this in future (zbs->DAL->quotes->addUpdateQuoteStatus directly) - function zeroBS_markQuoteAccepted($qID=-1,$quoteSignedBy=''){ +function zeroBS_markQuoteAccepted( $qID = -1, $quoteSignedBy = '' ) { - if ($qID !== -1){ + if ( $qID !== -1 ) { - global $zbs; + global $zbs; - return $zbs->DAL->quotes->addUpdateQuoteAccepted(array( - 'id' => $qID, + return $zbs->DAL->quotes->addUpdateQuoteAccepted( + array( + 'id' => $qID, 'accepted' => time(), 'signedby' => $quoteSignedBy, - 'ip' => zeroBSCRM_getRealIpAddr() - )); - - } - - return false; + 'ip' => zeroBSCRM_getRealIpAddr(), + ) + ); } + return false; +} + #} UNMarks a quote as "accepted" and saves as much related data as poss on accepter // again, use DAL to do this in future (zbs->DAL->quotes->addUpdateQuoteStatus directly) - function zeroBS_markQuoteUnAccepted($qID=-1){ - - if ($qID !== -1){ +function zeroBS_markQuoteUnAccepted( $qID = -1 ) { - global $zbs; - - return $zbs->DAL->quotes->addUpdateQuoteAccepted(array( - 'id' => $qID, - 'accepted' => '' - )); + if ( $qID !== -1 ) { - } + global $zbs; - return false; + return $zbs->DAL->quotes->addUpdateQuoteAccepted( + array( + 'id' => $qID, + 'accepted' => '', + ) + ); } - // Please use direct dal calls in future work. - function zeroBS_getQuotes( - - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false, - $searchPhrase='', - $inArray=array(), - $sortByField='', - $sortOrder='DESC', - $quickFilters=array(), - $hasTagIDs=array() - - ){ - - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; - - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; - - // make ARGS - $args = array( - - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArray, - 'quickFilters' => $quickFilters, - 'isTagged' => $hasTagIDs, - - 'withAssigned' => $withCustomerDeets, - - 'sortByField' => $sortByField, - 'sortOrder' => $sortOrder, - 'page' => $actualPage, - 'perPage' => $perPage, - - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE) + return false; +} +// Please use direct dal calls in future work. +function zeroBS_getQuotes( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false, + $searchPhrase = '', + $inArray = array(), + $sortByField = '', + $sortOrder = 'DESC', + $quickFilters = array(), + $hasTagIDs = array() +) { - ); + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; - return $zbs->DAL->quotes->getQuotes($args); + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; } + // make ARGS + $args = array( - // Please use direct dal calls in future work. - function zeroBS_getQuotesCountIncParams( + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArray, + 'quickFilters' => $quickFilters, + 'isTagged' => $hasTagIDs, - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false, - $searchPhrase='', - $inArray=array(), - $sortByField='', - $sortOrder='DESC', - $quickFilters=array(), - $hasTagIDs=array() + 'withAssigned' => $withCustomerDeets, - ){ + 'sortByField' => $sortByField, + 'sortOrder' => $sortOrder, + 'page' => $actualPage, + 'perPage' => $perPage, - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + ); - // make ARGS - $args = array( + return $zbs->DAL->quotes->getQuotes( $args ); +} - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArray, - 'quickFilters' => $quickFilters, - 'isTagged' => $hasTagIDs, +// Please use direct dal calls in future work. +function zeroBS_getQuotesCountIncParams( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false, + $searchPhrase = '', + $inArray = array(), + $sortByField = '', + $sortOrder = 'DESC', + $quickFilters = array(), + $hasTagIDs = array() +) { - // just count thx - 'count' => true, - 'withAssigned' => false, + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; - //'sortByField' => $sortByField, - //'sortOrder' => $sortOrder, - 'page' => -1, - 'perPage' => -1, + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; + } - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE) + // make ARGS + $args = array( + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArray, + 'quickFilters' => $quickFilters, + 'isTagged' => $hasTagIDs, - ); + // just count thx + 'count' => true, + 'withAssigned' => false, - return $zbs->DAL->quotes->getQuotes($args); - } + // 'sortByField' => $sortByField, + // 'sortOrder' => $sortOrder, + 'page' => -1, + 'perPage' => -1, - // Please use direct dal calls in future work. - function zeroBS_getQuotesForCustomer( + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), - $customerID=-1, - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false, - $withQuoteBuilderData=true + ); - ){ + return $zbs->DAL->quotes->getQuotes( $args ); +} - global $zbs; +// Please use direct dal calls in future work. +function zeroBS_getQuotesForCustomer( + $customerID = -1, + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false, + $withQuoteBuilderData = true // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- legacy API parameter. +) { - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + global $zbs; - // make ARGS - $args = array( + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; + } - // Search/Filtering (leave as false to ignore) - 'assignedContact' => $customerID, + // make ARGS + $args = array( - // with contact? - 'withAssigned' => $withCustomerDeets, + // Search/Filtering (leave as false to ignore) + 'assignedContact' => $customerID, - 'sortByField' => 'ID', - 'sortOrder' => 'DESC' , - 'page' => $actualPage, - 'perPage' => $perPage, + // with contact? + 'withAssigned' => $withCustomerDeets, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE) + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', + 'page' => $actualPage, + 'perPage' => $perPage, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), - ); + ); - return $zbs->DAL->quotes->getQuotes($args); - } + return $zbs->DAL->quotes->getQuotes( $args ); +} // Please use direct dal calls in future work. // phpcs:ignore Squiz.Commenting.FunctionComment.WrongStyle @@ -3849,317 +3966,309 @@ function zeroBS_getQuoteTemplate( $quoteTemplateID = -1 ) { // phpcs:ignore Word return false; } - // Please use direct dal calls in future work. +// Please use direct dal calls in future work. function zeroBS_getQuoteTemplates( $withFullDetails = false, $perPage = 10, $page = 0, $searchPhrase = '' ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,Squiz.Commenting.FunctionComment.WrongStyle - global $zbs; - return $zbs->DAL->quotetemplates->getQuotetemplates(array( - 'searchPhrase' => $searchPhrase, - 'page' => $page, - 'perPage' => $perPage, - 'checkDefaults' => true - )); - - /* was returning - - core post + - $retObj['meta'] = get_post_meta($ele->ID, 'zbs_quotemplate_meta', true); - $retObj['zbsdefault'] = get_post_meta($ele->ID, 'zbsdefault', true); + global $zbs; + return $zbs->DAL->quotetemplates->getQuotetemplates( + array( + 'searchPhrase' => $searchPhrase, + 'page' => $page, + 'perPage' => $perPage, + 'checkDefaults' => true, + ) + ); - */ - } + /* + was returning - // retrieves a count for listview retrievedata, really - function zeroBS_getQuoteTemplatesCountIncParams($withFullDetails=false,$perPage=10,$page=0,$searchPhrase=''){ + core post + + $retObj['meta'] = get_post_meta($ele->ID, 'zbs_quotemplate_meta', true); + $retObj['zbsdefault'] = get_post_meta($ele->ID, 'zbsdefault', true); - global $zbs; + */ +} - return $zbs->DAL->quotetemplates->getQuotetemplates(array( - 'searchPhrase' => $searchPhrase, - 'count' => 1, - 'page' => -1, - 'perPage' => -1, - )); - } +// retrieves a count for listview retrievedata, really +function zeroBS_getQuoteTemplatesCountIncParams( $withFullDetails = false, $perPage = 10, $page = 0, $searchPhrase = '' ) { - // moves a quote from being assigned to one cust, to another - // this is a fill-in to match old DAL2 func, however DAL3+ can accept customer/company, - // ... so use the proper $DAL->addUpdateObjectLinks for fresh code - function zeroBSCRM_changeQuoteCustomer($id=-1,$contactID=0){ + global $zbs; - if (!empty($id) && $contactID > 0){ + return $zbs->DAL->quotetemplates->getQuotetemplates( + array( + 'searchPhrase' => $searchPhrase, + 'count' => 1, + 'page' => -1, + 'perPage' => -1, + ) + ); +} - global $zbs; - return $zbs->DAL->quotes->addUpdateObjectLinks($id,array($contactID),ZBS_TYPE_CONTACT); +// moves a quote from being assigned to one cust, to another +// this is a fill-in to match old DAL2 func, however DAL3+ can accept customer/company, +// ... so use the proper $DAL->addUpdateObjectLinks for fresh code +function zeroBSCRM_changeQuoteCustomer( $id = -1, $contactID = 0 ) { - } + if ( ! empty( $id ) && $contactID > 0 ) { - return false; + global $zbs; + return $zbs->DAL->quotes->addUpdateObjectLinks( $id, array( $contactID ), ZBS_TYPE_CONTACT ); } -/* ====================================================== - / Quote helpers - ====================================================== */ + return false; +} -/* ====================================================== - Invoice helpers - ====================================================== */ +/* +====================================================== + / Quote helpers +====================================================== */ - // Get next available sequential invoice ID - function zeroBSCRM_getNextInvoiceID(){ +/* +====================================================== + Invoice helpers +====================================================== */ - // DAL3: - $potential = (int)zeroBSCRM_getSetting('invoiceindx',true); - if ($potential > 0) { - return $potential+1; - } - else { - return zeroBSCRM_getInvoiceOffset()+1; - } + // Get next available sequential invoice ID +function zeroBSCRM_getNextInvoiceID() { + // DAL3: + $potential = (int) zeroBSCRM_getSetting( 'invoiceindx', true ); + if ( $potential > 0 ) { + return $potential + 1; + } else { + return zeroBSCRM_getInvoiceOffset() + 1; } +} // set the current max used invid - function zeroBSCRM_setMaxInvoiceID($newMax=0){ +function zeroBSCRM_setMaxInvoiceID( $newMax = 0 ) { - $existingMax = zeroBSCRM_getNextInvoiceID(); + $existingMax = zeroBSCRM_getNextInvoiceID(); - if ($newMax >= $existingMax){ + if ( $newMax >= $existingMax ) { - // DAL3: - global $zbs; - return $zbs->settings->update('invoiceindx',$newMax); - - } + // DAL3: + global $zbs; + return $zbs->settings->update( 'invoiceindx', $newMax ); - return false; } - // Minified get offset func - function zeroBSCRM_getInvoiceOffset(){ - - global $zbs; - // this only exists on legacy sites - $offset = (int)$zbs->settings->get( 'invoffset' ); + return false; +} - if ( empty($offset) || $offset < 0 ) { - $offset = 0; - } + // Minified get offset func +function zeroBSCRM_getInvoiceOffset() { - return $offset; + global $zbs; + // this only exists on legacy sites + $offset = (int) $zbs->settings->get( 'invoffset' ); + if ( empty( $offset ) || $offset < 0 ) { + $offset = 0; } - // outdated, outmoded, use proper ->DAL calls not this in fresh code - function zeroBS_getInvoices( + return $offset; +} - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false, - $searchPhrase='', - $inArray=array(), - $sortByField='', - $sortOrder='DESC', - $quickFilters=array(), - $hasTagIDs=array() + // outdated, outmoded, use proper ->DAL calls not this in fresh code +function zeroBS_getInvoices( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false, + $searchPhrase = '', + $inArray = array(), + $sortByField = '', + $sortOrder = 'DESC', + $quickFilters = array(), + $hasTagIDs = array() +) { - ){ + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; + } - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + // make ARGS + $args = array( - // make ARGS - $args = array( + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArray, + 'quickFilters' => $quickFilters, + 'isTagged' => $hasTagIDs, - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArray, - 'quickFilters' => $quickFilters, - 'isTagged' => $hasTagIDs, + 'withAssigned' => $withCustomerDeets, - 'withAssigned' => $withCustomerDeets, + 'sortByField' => $sortByField, + 'sortOrder' => $sortOrder, + 'page' => $actualPage, + 'perPage' => $perPage, - 'sortByField' => $sortByField, - 'sortOrder' => $sortOrder, - 'page' => $actualPage, - 'perPage' => $perPage, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE) + ); + return $zbs->DAL->invoices->getInvoices( $args ); +} - ); + // outdated, outmoded, use proper ->DAL calls not this in fresh code +function zeroBS_getInvoicesCountIncParams( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false, + $searchPhrase = '', + $inArray = array(), + $sortByField = '', + $sortOrder = 'DESC', + $quickFilters = array(), + $hasTagIDs = array() +) { - return $zbs->DAL->invoices->getInvoices($args); + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; } - // outdated, outmoded, use proper ->DAL calls not this in fresh code - function zeroBS_getInvoicesCountIncParams( - - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false, - $searchPhrase='', - $inArray=array(), - $sortByField='', - $sortOrder='DESC', - $quickFilters=array(), - $hasTagIDs=array() + // make ARGS + $args = array( - ){ + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArray, + 'quickFilters' => $quickFilters, + 'isTagged' => $hasTagIDs, - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; + // just count thx + 'count' => true, + 'withAssigned' => false, - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + // 'sortByField' => $sortByField, + // 'sortOrder' => $sortOrder, + 'page' => -1, + 'perPage' => -1, - // make ARGS - $args = array( + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArray, - 'quickFilters' => $quickFilters, - 'isTagged' => $hasTagIDs, + ); - // just count thx - 'count' => true, - 'withAssigned' => false, + return $zbs->DAL->invoices->getInvoices( $args ); +} - //'sortByField' => $sortByField, - //'sortOrder' => $sortOrder, - 'page' => -1, - 'perPage' => -1, + // DAL3 translated. + // invs model now looks diff so adapt everywhere with getInvoice +function zeroBS_getInvoice( $invoiceID = -1 ) { - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE) + if ( $invoiceID > 0 ) { + global $zbs; - ); + return $zbs->DAL->invoices->getInvoice( $invoiceID ); - return $zbs->DAL->invoices->getInvoices($args); } + return false; +} - // DAL3 translated. - // invs model now looks diff so adapt everywhere with getInvoice - function zeroBS_getInvoice($invoiceID=-1){ - - if ($invoiceID > 0){ - - global $zbs; + // just do direct call in future, plz +function zeroBS_getInvoicesForCustomer( + $customerID = -1, + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false, + $orderBy = 'ID', + $order = 'DESC' +) { - return $zbs->DAL->invoices->getInvoice($invoiceID); + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; - } - - return false; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; } - // just do direct call in future, plz - function zeroBS_getInvoicesForCustomer( + // make ARGS + $args = array( - $customerID=-1, - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false, - $orderBy='ID', - $order='DESC' + // Search/Filtering (leave as false to ignore) + 'assignedContact' => $customerID, - ){ + // with contact? + 'withAssigned' => $withCustomerDeets, - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; + 'sortByField' => $orderBy, + 'sortOrder' => $order, + 'page' => $actualPage, + 'perPage' => $perPage, - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), - // make ARGS - $args = array( + ); - // Search/Filtering (leave as false to ignore) - 'assignedContact' => $customerID, + return $zbs->DAL->invoices->getInvoices( $args ); +} - // with contact? - 'withAssigned' => $withCustomerDeets, + // moves a inv from being assigned to one cust, to another + // this is a fill-in to match old DAL2 func, however DAL3+ can accept customer/company, + // ... so use the proper $DAL->addUpdateObjectLinks for fresh code +function zeroBSCRM_changeInvoiceCustomer( $id = -1, $contactID = 0 ) { - 'sortByField' => $orderBy, - 'sortOrder' => $order, - 'page' => $actualPage, - 'perPage' => $perPage, + if ( ! empty( $id ) && $contactID > 0 ) { - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE) - - - ); - - return $zbs->DAL->invoices->getInvoices($args); - } - - // moves a inv from being assigned to one cust, to another - // this is a fill-in to match old DAL2 func, however DAL3+ can accept customer/company, - // ... so use the proper $DAL->addUpdateObjectLinks for fresh code - function zeroBSCRM_changeInvoiceCustomer($id=-1,$contactID=0){ - - if (!empty($id) && $contactID > 0){ - - global $zbs; - return $zbs->DAL->invoices->addUpdateObjectLinks($id,array($contactID),ZBS_TYPE_CONTACT); - - } - - return false; + global $zbs; + return $zbs->DAL->invoices->addUpdateObjectLinks( $id, array( $contactID ), ZBS_TYPE_CONTACT ); } + return false; +} // grabs invoice customer - function zeroBSCRM_getInvoiceCustomer($invID=-1){ - +function zeroBSCRM_getInvoiceCustomer( $invID = -1 ) { - if (!empty($invWPID)){ + if ( ! empty( $invWPID ) ) { - global $zbs; - return $zbs->DAL->invoices->getInvoiceContact($invID); - - } - - return false; + global $zbs; + return $zbs->DAL->invoices->getInvoiceContact( $invID ); } + return false; +} + // updates a stauts, if inv exists. // use $zbs->DAL->invoices->setInvoiceStatus($invoiceID,$statusStr); for new code - function zeroBS_updateInvoiceStatus($invoiceID=-1,$statusStr='Draft'){ - - if ( in_array( $statusStr, zeroBSCRM_getInvoicesStatuses() ) ){ +function zeroBS_updateInvoiceStatus( $invoiceID = -1, $statusStr = 'Draft' ) { - $potentialInvoice = zeroBS_getInvoice($invoiceID); - if (isset($potentialInvoice) && is_array($potentialInvoice)){ + if ( in_array( $statusStr, zeroBSCRM_getInvoicesStatuses() ) ) { - // dal3 - global $zbs; - return $zbs->DAL->invoices->setInvoiceStatus($invoiceID,$statusStr); + $potentialInvoice = zeroBS_getInvoice( $invoiceID ); + if ( isset( $potentialInvoice ) && is_array( $potentialInvoice ) ) { - } + // dal3 + global $zbs; + return $zbs->DAL->invoices->setInvoiceStatus( $invoiceID, $statusStr ); } - - return false; - } + return false; +} -/* ====================================================== - Invoice 3.0 helpers - ====================================================== */ +/* +====================================================== + Invoice 3.0 helpers +====================================================== */ // this function probably becomes defunct when DAL ready. Is cos right now, if invoice_meta = '' then it's a new invoice, so should return defaults. function zeroBSCRM_get_invoice_defaults( $obj_id = -1 ) { @@ -4167,14 +4276,14 @@ function zeroBSCRM_get_invoice_defaults( $obj_id = -1 ) { // Settings $settings = zeroBSCRM_get_invoice_settings(); - $now = time(); + $now = time(); $default_date = jpcrm_uts_to_date_str( $now, 'Y-m-d' ); // If it has reference as autonumber, determine next number. if ( $settings['reftype'] === 'autonumber' ) { $next_number = $settings['refnextnum']; - $prefix = $settings['refprefix']; - $suffix = $settings['refsuffix']; + $prefix = $settings['refprefix']; + $suffix = $settings['refsuffix']; $id_override = $prefix . $next_number . $suffix; } else { $id_override = $settings['defaultref']; @@ -4209,156 +4318,148 @@ function zeroBSCRM_get_invoice_defaults( $obj_id = -1 ) { ), ); return $defaults; - } +#} wrapper as right now it was loading the full settings into the page. Tidy up page to have the translations here. +#} WH - is it possible that some languages here will mess with the output? character encoding wise? +function zeroBSCRM_get_invoice_settings() { - #} wrapper as right now it was loading the full settings into the page. Tidy up page to have the translations here. - #} WH - is it possible that some languages here will mess with the output? character encoding wise? - function zeroBSCRM_get_invoice_settings(){ - - global $zbs; - - $all_settings = $zbs->settings->getAll(); - - $reference_label = zbs_ifAV( $all_settings,'reflabel','' ); - if( empty( $reference_label ) ) { - $reference_label = __('Reference', 'zero-bs-crm'); - } - - // Check if it is the first invoice - $first_invoice = ! $zbs->DAL->invoices->getFullCount(); - - $invoice_settings = array( - 'b2bmode' => zbs_ifAV($all_settings,'companylevelcustomers',false), - 'invtax' => zbs_ifAV($all_settings,'invtax',''), - 'invpandp' => zbs_ifAV($all_settings,'invpandp',''), - 'invdis' => zbs_ifAV($all_settings,'invdis',''), - 'logo' => zbs_ifAV($all_settings,'invoicelogourl',''), - 'bizname' => zbs_ifAV($all_settings,'businessname',''), - 'yourname' => zbs_ifAV($all_settings,'businessyourname',''), - 'defaultref' => zbs_ifAV($all_settings,'defaultref',''), - 'reftype' => zbs_ifAV($all_settings,'reftype',''), - 'refprefix' => zbs_ifAV($all_settings,'refprefix',''), - 'refnextnum' => zbs_ifAV($all_settings,'refnextnum',''), - 'refsuffix' => zbs_ifAV($all_settings,'refsuffix',''), - 'isfirstinv' => $first_invoice, - 'invhash' => zbs_ifAV($all_settings,'easyaccesslinks',''), - 'hideid' => zbs_ifAV($all_settings,'invid',false), - 'businessextra' => nl2br(zeroBSCRM_textExpose(zbs_ifAV($all_settings,'businessextra',''))), - 'businessyouremail' => zbs_ifAV($all_settings,'businessyouremail',''), - 'businessyoururl' => zbs_ifAV($all_settings,'businessyoururl',''), - 'settings_slug' => admin_url("admin.php?page=" . $zbs->slugs['settings']) . "&tab=invbuilder", - 'biz_settings_slug' => admin_url("admin.php?page=" . $zbs->slugs['settings']) . "&tab=bizinfo", - 'addnewcontacturl' => jpcrm_esc_link('create',-1,'zerobs_customer'), - 'addnewcompanyurl' => jpcrm_esc_link('create',-1,'zerobs_company'), - 'contacturlprefix' => jpcrm_esc_link('edit',-1,'zerobs_customer',true), - 'companyurlprefix' => jpcrm_esc_link('edit',-1,'zerobs_company',true), - 'lang' => array( - 'invoice_number' => zeroBSCRM_slashOut(__('ID', 'zero-bs-crm'),true), - 'invoice_date' => zeroBSCRM_slashOut(__('Invoice date', 'zero-bs-crm'),true), - 'invoice_status' => zeroBSCRM_slashOut( __( 'Status', 'zero-bs-crm' ), true ), - 'status_unpaid' => zeroBSCRM_slashOut( __( 'Unpaid', 'zero-bs-crm' ), true ), - 'status_paid' => zeroBSCRM_slashOut( __( 'Paid', 'zero-bs-crm' ), true ), - 'status_overdue' => zeroBSCRM_slashOut( __( 'Overdue', 'zero-bs-crm' ), true ), - 'status_draft' => zeroBSCRM_slashOut( __( 'Draft', 'zero-bs-crm' ), true ), - 'status_deleted' => zeroBSCRM_slashOut( __( 'Deleted', 'zero-bs-crm' ), true ), - 'reference' => zeroBSCRM_slashOut( $reference_label,true), - 'autogenerated' => zeroBSCRM_slashOut( __('Generated on save', 'zero-bs-crm'),true), - 'refsettings' => zeroBSCRM_slashOut( __('Set up your reference type here', 'zero-bs-crm'),true), - 'nextref' => zeroBSCRM_slashOut( __('Next reference expected', 'zero-bs-crm'),true), - 'due_date' => zeroBSCRM_slashOut(__('Due date', 'zero-bs-crm'),true), - 'frequency' => zeroBSCRM_slashOut(__('Frequency', 'zero-bs-crm'),true), - 'update' => zeroBSCRM_slashOut(__('Update', 'zero-bs-crm'),true), - 'remove' => zeroBSCRM_slashOut(__('Remove', 'zero-bs-crm'),true), - 'biz_info' => zeroBSCRM_slashOut(__('Your business information', 'zero-bs-crm'),true), - 'add_edit' => zeroBSCRM_slashOut(__('Edit '.jpcrm_label_company().' Details', 'zero-bs-crm'),true), - 'add_logo' => zeroBSCRM_slashOut(__('Add your logo', 'zero-bs-crm'),true), - 'send_to' => zeroBSCRM_slashOut(__('Assign invoice to', 'zero-bs-crm'),true), - 'customise' => zeroBSCRM_slashOut(__('Customise', 'zero-bs-crm'),true), - 'hours' => zeroBSCRM_slashOut(__('Hours', 'zero-bs-crm'),true), - 'quantity' => zeroBSCRM_slashOut(__('Quantity', 'zero-bs-crm'),true), - 'description' => zeroBSCRM_slashOut(__('Description', 'zero-bs-crm'),true), - 'price' => zeroBSCRM_slashOut(__('Price', 'zero-bs-crm'),true), - 'rate' => zeroBSCRM_slashOut(__('Rate', 'zero-bs-crm'),true), - 'tax' => zeroBSCRM_slashOut(__('Tax', 'zero-bs-crm'),true), - 'add_row' => zeroBSCRM_slashOut(__('Add row', 'zero-bs-crm'),true), - 'remove_row' => zeroBSCRM_slashOut(__('Remove row', 'zero-bs-crm'),true), - 'amount' => zeroBSCRM_slashOut(__('Amount', 'zero-bs-crm'),true), - 'discount' => zeroBSCRM_slashOut(__('Discount', 'zero-bs-crm'),true), - 'shipping' => zeroBSCRM_slashOut(__('Shipping', 'zero-bs-crm'),true), - 'tax_on_shipping' => zeroBSCRM_slashOut(__('Tax on shipping', 'zero-bs-crm'),true), - 'due' => array( - 'none' => zeroBSCRM_slashOut(__('No due date', 'zero-bs-crm'),true), - 'on' => zeroBSCRM_slashOut(__('Due on receipt', 'zero-bs-crm'),true), - 'ten' => zeroBSCRM_slashOut(__('Due in 10 days', 'zero-bs-crm'),true), - 'fifteen' => zeroBSCRM_slashOut(__('Due in 15 days', 'zero-bs-crm'),true), - 'thirty' => zeroBSCRM_slashOut(__('Due in 30 days', 'zero-bs-crm'),true), - 'fortyfive' => zeroBSCRM_slashOut(__('Due in 45 days', 'zero-bs-crm'),true), - 'sixty' => zeroBSCRM_slashOut(__('Due in 60 days', 'zero-bs-crm'),true), - 'ninety' => zeroBSCRM_slashOut(__('Due in 90 days', 'zero-bs-crm'),true) - ), - 'preview' => zeroBSCRM_slashOut(__('Preview', 'zero-bs-crm'),true), - 'dl_pdf' => zeroBSCRM_slashOut(__('Download PDF', 'zero-bs-crm'),true), - 'bill_to' => zeroBSCRM_slashOut(__('Enter email address or name', 'zero-bs-crm'),true), - 'edit_record' => zeroBSCRM_slashOut(__('Edit record', 'zero-bs-crm'),true), - 'no_tax' => zeroBSCRM_slashOut(__('None', 'zero-bs-crm'),true), - 'taxgrouplabel' => zeroBSCRM_slashOut(__('Rates', 'zero-bs-crm'),true), - 'subtotal' => zeroBSCRM_slashOut(__('Subtotal', 'zero-bs-crm'),true), - 'total' => zeroBSCRM_slashOut(__('Total', 'zero-bs-crm'),true), - 'amount_due' => zeroBSCRM_slashOut(__('Amount due', 'zero-bs-crm'),true), - 'partial_table' => zeroBSCRM_slashOut(__('Payments', 'zero-bs-crm'),true), - 'incomplete' => zeroBSCRM_slashOut(__('Incomplete', 'zero-bs-crm'),true), - 'rowtitleplaceholder' => zeroBSCRM_slashOut(__('Item title', 'zero-bs-crm'),true), - 'rowdescplaceholder' => zeroBSCRM_slashOut(__('Item description', 'zero-bs-crm'),true), - 'noname' => zeroBSCRM_slashOut(__('Unnamed', 'zero-bs-crm'),true), // no name on typeahead, - 'noemail' => zeroBSCRM_slashOut(__('No email', 'zero-bs-crm'),true), // no email on typeahead, - 'contact' => zeroBSCRM_slashOut(__('Contact', 'zero-bs-crm'),true), // contact view button (if assigned) - 'company' => zeroBSCRM_slashOut(jpcrm_label_company(),true), // contact view button (if assigned) - 'view' => zeroBSCRM_slashOut(__('View', 'zero-bs-crm'),true), - 'addnewcontact' => zeroBSCRM_slashOut(__('Add new contact', 'zero-bs-crm'),true), - 'newcompany' => zeroBSCRM_slashOut(__('new '.jpcrm_label_company(), 'zero-bs-crm'),true), - 'or' => zeroBSCRM_slashOut(__('or', 'zero-bs-crm'),true), - - // send email modal - 'send_email' => zeroBSCRM_slashOut(__('Email invoice', 'zero-bs-crm'),true), - 'sendthisemail' => zeroBSCRM_slashOut(__('Send this invoice via email:', 'zero-bs-crm'),true), - 'toemail' => zeroBSCRM_slashOut(__('To email:', 'zero-bs-crm'),true), - 'toemailplaceholder' => zeroBSCRM_slashOut(__('e.g. mike@gmail.com', 'zero-bs-crm'),true), - 'attachassoc' => zeroBSCRM_slashOut(__('Attach associated files', 'zero-bs-crm'),true), - 'attachpdf' => zeroBSCRM_slashOut(__('Attach as PDF', 'zero-bs-crm'),true), - 'sendthemail' => zeroBSCRM_slashOut(__('Send', 'zero-bs-crm'),true), - 'sendneedsassignment' => zeroBSCRM_slashOut(__('To send an email, this invoice needs to be assigned to a contact or company with a valid email address.', 'zero-bs-crm'),true), - 'sendingemail' => zeroBSCRM_slashOut(__('Sending email...', 'zero-bs-crm'),true), - 'senttitle' => zeroBSCRM_slashOut(__('Invoice sent', 'zero-bs-crm'),true), - 'sent' => zeroBSCRM_slashOut(__('Your invoice has been sent by email', 'zero-bs-crm'),true), - 'senderrortitle' => zeroBSCRM_slashOut(__('Error sending', 'zero-bs-crm'),true), - 'senderror' => zeroBSCRM_slashOut(__('There was an error sending this invoice via email.', 'zero-bs-crm'),true), - - - - ) - ); - return $invoice_settings; - - } - - #} Invoicing Pro - needs product index - // WH: Don't like the lazy naming - function zeroBSCRM_getProductIndex(){ - $product_index = array(); - apply_filters('zbs_product_index_array', $product_index); - return $product_index; - } + global $zbs; - // wrapper now for zeroBSCRM_hashes_GetObjFromHash - function zeroBSCRM_quotes_getFromHash($hash = ''){ + $all_settings = $zbs->settings->getAll(); + + $reference_label = zbs_ifAV( $all_settings, 'reflabel', '' ); + if ( empty( $reference_label ) ) { + $reference_label = __( 'Reference', 'zero-bs-crm' ); + } + + // Check if it is the first invoice + $first_invoice = ! $zbs->DAL->invoices->getFullCount(); + + $invoice_settings = array( + 'b2bmode' => zbs_ifAV( $all_settings, 'companylevelcustomers', false ), + 'invtax' => zbs_ifAV( $all_settings, 'invtax', '' ), + 'invpandp' => zbs_ifAV( $all_settings, 'invpandp', '' ), + 'invdis' => zbs_ifAV( $all_settings, 'invdis', '' ), + 'logo' => zbs_ifAV( $all_settings, 'invoicelogourl', '' ), + 'bizname' => zbs_ifAV( $all_settings, 'businessname', '' ), + 'yourname' => zbs_ifAV( $all_settings, 'businessyourname', '' ), + 'defaultref' => zbs_ifAV( $all_settings, 'defaultref', '' ), + 'reftype' => zbs_ifAV( $all_settings, 'reftype', '' ), + 'refprefix' => zbs_ifAV( $all_settings, 'refprefix', '' ), + 'refnextnum' => zbs_ifAV( $all_settings, 'refnextnum', '' ), + 'refsuffix' => zbs_ifAV( $all_settings, 'refsuffix', '' ), + 'isfirstinv' => $first_invoice, + 'invhash' => zbs_ifAV( $all_settings, 'easyaccesslinks', '' ), + 'hideid' => zbs_ifAV( $all_settings, 'invid', false ), + 'businessextra' => nl2br( zeroBSCRM_textExpose( zbs_ifAV( $all_settings, 'businessextra', '' ) ) ), + 'businessyouremail' => zbs_ifAV( $all_settings, 'businessyouremail', '' ), + 'businessyoururl' => zbs_ifAV( $all_settings, 'businessyoururl', '' ), + 'settings_slug' => admin_url( 'admin.php?page=' . $zbs->slugs['settings'] ) . '&tab=invbuilder', + 'biz_settings_slug' => admin_url( 'admin.php?page=' . $zbs->slugs['settings'] ) . '&tab=bizinfo', + 'addnewcontacturl' => jpcrm_esc_link( 'create', -1, 'zerobs_customer' ), + 'addnewcompanyurl' => jpcrm_esc_link( 'create', -1, 'zerobs_company' ), + 'contacturlprefix' => jpcrm_esc_link( 'edit', -1, 'zerobs_customer', true ), + 'companyurlprefix' => jpcrm_esc_link( 'edit', -1, 'zerobs_company', true ), + 'lang' => array( + 'invoice_number' => zeroBSCRM_slashOut( __( 'ID', 'zero-bs-crm' ), true ), + 'invoice_date' => zeroBSCRM_slashOut( __( 'Invoice date', 'zero-bs-crm' ), true ), + 'invoice_status' => zeroBSCRM_slashOut( __( 'Status', 'zero-bs-crm' ), true ), + 'status_unpaid' => zeroBSCRM_slashOut( __( 'Unpaid', 'zero-bs-crm' ), true ), + 'status_paid' => zeroBSCRM_slashOut( __( 'Paid', 'zero-bs-crm' ), true ), + 'status_overdue' => zeroBSCRM_slashOut( __( 'Overdue', 'zero-bs-crm' ), true ), + 'status_draft' => zeroBSCRM_slashOut( __( 'Draft', 'zero-bs-crm' ), true ), + 'status_deleted' => zeroBSCRM_slashOut( __( 'Deleted', 'zero-bs-crm' ), true ), + 'reference' => zeroBSCRM_slashOut( $reference_label, true ), + 'autogenerated' => zeroBSCRM_slashOut( __( 'Generated on save', 'zero-bs-crm' ), true ), + 'refsettings' => zeroBSCRM_slashOut( __( 'Set up your reference type here', 'zero-bs-crm' ), true ), + 'nextref' => zeroBSCRM_slashOut( __( 'Next reference expected', 'zero-bs-crm' ), true ), + 'due_date' => zeroBSCRM_slashOut( __( 'Due date', 'zero-bs-crm' ), true ), + 'frequency' => zeroBSCRM_slashOut( __( 'Frequency', 'zero-bs-crm' ), true ), + 'update' => zeroBSCRM_slashOut( __( 'Update', 'zero-bs-crm' ), true ), + 'remove' => zeroBSCRM_slashOut( __( 'Remove', 'zero-bs-crm' ), true ), + 'biz_info' => zeroBSCRM_slashOut( __( 'Your business information', 'zero-bs-crm' ), true ), + 'add_edit' => zeroBSCRM_slashOut( __( 'Edit ' . jpcrm_label_company() . ' Details', 'zero-bs-crm' ), true ), + 'add_logo' => zeroBSCRM_slashOut( __( 'Add your logo', 'zero-bs-crm' ), true ), + 'send_to' => zeroBSCRM_slashOut( __( 'Assign invoice to', 'zero-bs-crm' ), true ), + 'customise' => zeroBSCRM_slashOut( __( 'Customise', 'zero-bs-crm' ), true ), + 'hours' => zeroBSCRM_slashOut( __( 'Hours', 'zero-bs-crm' ), true ), + 'quantity' => zeroBSCRM_slashOut( __( 'Quantity', 'zero-bs-crm' ), true ), + 'description' => zeroBSCRM_slashOut( __( 'Description', 'zero-bs-crm' ), true ), + 'price' => zeroBSCRM_slashOut( __( 'Price', 'zero-bs-crm' ), true ), + 'rate' => zeroBSCRM_slashOut( __( 'Rate', 'zero-bs-crm' ), true ), + 'tax' => zeroBSCRM_slashOut( __( 'Tax', 'zero-bs-crm' ), true ), + 'add_row' => zeroBSCRM_slashOut( __( 'Add row', 'zero-bs-crm' ), true ), + 'remove_row' => zeroBSCRM_slashOut( __( 'Remove row', 'zero-bs-crm' ), true ), + 'amount' => zeroBSCRM_slashOut( __( 'Amount', 'zero-bs-crm' ), true ), + 'discount' => zeroBSCRM_slashOut( __( 'Discount', 'zero-bs-crm' ), true ), + 'shipping' => zeroBSCRM_slashOut( __( 'Shipping', 'zero-bs-crm' ), true ), + 'tax_on_shipping' => zeroBSCRM_slashOut( __( 'Tax on shipping', 'zero-bs-crm' ), true ), + 'due' => array( + 'none' => zeroBSCRM_slashOut( __( 'No due date', 'zero-bs-crm' ), true ), + 'on' => zeroBSCRM_slashOut( __( 'Due on receipt', 'zero-bs-crm' ), true ), + 'ten' => zeroBSCRM_slashOut( __( 'Due in 10 days', 'zero-bs-crm' ), true ), + 'fifteen' => zeroBSCRM_slashOut( __( 'Due in 15 days', 'zero-bs-crm' ), true ), + 'thirty' => zeroBSCRM_slashOut( __( 'Due in 30 days', 'zero-bs-crm' ), true ), + 'fortyfive' => zeroBSCRM_slashOut( __( 'Due in 45 days', 'zero-bs-crm' ), true ), + 'sixty' => zeroBSCRM_slashOut( __( 'Due in 60 days', 'zero-bs-crm' ), true ), + 'ninety' => zeroBSCRM_slashOut( __( 'Due in 90 days', 'zero-bs-crm' ), true ), + ), + 'preview' => zeroBSCRM_slashOut( __( 'Preview', 'zero-bs-crm' ), true ), + 'dl_pdf' => zeroBSCRM_slashOut( __( 'Download PDF', 'zero-bs-crm' ), true ), + 'bill_to' => zeroBSCRM_slashOut( __( 'Enter email address or name', 'zero-bs-crm' ), true ), + 'edit_record' => zeroBSCRM_slashOut( __( 'Edit record', 'zero-bs-crm' ), true ), + 'no_tax' => zeroBSCRM_slashOut( __( 'None', 'zero-bs-crm' ), true ), + 'taxgrouplabel' => zeroBSCRM_slashOut( __( 'Rates', 'zero-bs-crm' ), true ), + 'subtotal' => zeroBSCRM_slashOut( __( 'Subtotal', 'zero-bs-crm' ), true ), + 'total' => zeroBSCRM_slashOut( __( 'Total', 'zero-bs-crm' ), true ), + 'amount_due' => zeroBSCRM_slashOut( __( 'Amount due', 'zero-bs-crm' ), true ), + 'partial_table' => zeroBSCRM_slashOut( __( 'Payments', 'zero-bs-crm' ), true ), + 'incomplete' => zeroBSCRM_slashOut( __( 'Incomplete', 'zero-bs-crm' ), true ), + 'rowtitleplaceholder' => zeroBSCRM_slashOut( __( 'Item title', 'zero-bs-crm' ), true ), + 'rowdescplaceholder' => zeroBSCRM_slashOut( __( 'Item description', 'zero-bs-crm' ), true ), + 'noname' => zeroBSCRM_slashOut( __( 'Unnamed', 'zero-bs-crm' ), true ), // no name on typeahead, + 'noemail' => zeroBSCRM_slashOut( __( 'No email', 'zero-bs-crm' ), true ), // no email on typeahead, + 'contact' => zeroBSCRM_slashOut( __( 'Contact', 'zero-bs-crm' ), true ), // contact view button (if assigned) + 'company' => zeroBSCRM_slashOut( jpcrm_label_company(), true ), // contact view button (if assigned) + 'view' => zeroBSCRM_slashOut( __( 'View', 'zero-bs-crm' ), true ), + 'addnewcontact' => zeroBSCRM_slashOut( __( 'Add new contact', 'zero-bs-crm' ), true ), + 'newcompany' => zeroBSCRM_slashOut( __( 'new ' . jpcrm_label_company(), 'zero-bs-crm' ), true ), + 'or' => zeroBSCRM_slashOut( __( 'or', 'zero-bs-crm' ), true ), + + // send email modal + 'send_email' => zeroBSCRM_slashOut( __( 'Email invoice', 'zero-bs-crm' ), true ), + 'sendthisemail' => zeroBSCRM_slashOut( __( 'Send this invoice via email:', 'zero-bs-crm' ), true ), + 'toemail' => zeroBSCRM_slashOut( __( 'To email:', 'zero-bs-crm' ), true ), + 'toemailplaceholder' => zeroBSCRM_slashOut( __( 'e.g. mike@gmail.com', 'zero-bs-crm' ), true ), + 'attachassoc' => zeroBSCRM_slashOut( __( 'Attach associated files', 'zero-bs-crm' ), true ), + 'attachpdf' => zeroBSCRM_slashOut( __( 'Attach as PDF', 'zero-bs-crm' ), true ), + 'sendthemail' => zeroBSCRM_slashOut( __( 'Send', 'zero-bs-crm' ), true ), + 'sendneedsassignment' => zeroBSCRM_slashOut( __( 'To send an email, this invoice needs to be assigned to a contact or company with a valid email address.', 'zero-bs-crm' ), true ), + 'sendingemail' => zeroBSCRM_slashOut( __( 'Sending email...', 'zero-bs-crm' ), true ), + 'senttitle' => zeroBSCRM_slashOut( __( 'Invoice sent', 'zero-bs-crm' ), true ), + 'sent' => zeroBSCRM_slashOut( __( 'Your invoice has been sent by email', 'zero-bs-crm' ), true ), + 'senderrortitle' => zeroBSCRM_slashOut( __( 'Error sending', 'zero-bs-crm' ), true ), + 'senderror' => zeroBSCRM_slashOut( __( 'There was an error sending this invoice via email.', 'zero-bs-crm' ), true ), - return zeroBSCRM_hashes_GetObjFromHash($hash,-1,ZBS_TYPE_QUOTE); + ), + ); + return $invoice_settings; +} + #} Invoicing Pro - needs product index + // WH: Don't like the lazy naming +function zeroBSCRM_getProductIndex() { + $product_index = array(); + apply_filters( 'zbs_product_index_array', $product_index ); + return $product_index; +} - } + // wrapper now for zeroBSCRM_hashes_GetObjFromHash +function zeroBSCRM_quotes_getFromHash( $hash = '' ) { + return zeroBSCRM_hashes_GetObjFromHash( $hash, -1, ZBS_TYPE_QUOTE ); +} // NOTE ON FOLLOWING: // ... this is MS's centralised func which centralises Inv data req. but it's still clunky. @@ -4369,77 +4470,77 @@ function zeroBSCRM_quotes_getFromHash($hash = ''){ /** * This file has the various functions used to control the invoice metaboxes * Wrappers so can be used throughout and switched over when it comes to it - * + * * The current metabox output, has also been changed to draw with JS now given * the added complexity of the tax table and discount per line - * + * * The calculation routine has also been reviewed to calculate the tax due * AFTER the line items discount has been applied - * + * * Drawing a new line was already available in JS, but the initial load (new) and edit * were messily drawn in PHP - * + * * Now it simply stores the invoice meta as one big data JSON structure outlined below * data format described below - * + * * JSON object for invoice - * + * * invoiceObj = { - *! invoice_id: 5, // ID in the database - usually the invoice ID. - *! invoice_custom_id: -1 // the ID if over-written by settings (WH REMOVED, use id_override) - * - *! status: paid, // not defined in settings - should be? (draft, unpaid, paid, overdue) - * + * ! invoice_id: 5, // ID in the database - usually the invoice ID. + * ! invoice_custom_id: -1 // the ID if over-written by settings (WH REMOVED, use id_override) + * + * ! status: paid, // not defined in settings - should be? (draft, unpaid, paid, overdue) + * * preview_link: // generated from hash * pdf_dl_link: // downloaded on fly - * - *! hash: // the invoice hash (for front end accessible pages) - * - * pdf_template: // the template to use + * + * ! hash: // the invoice hash (for front end accessible pages) + * + * pdf_template: // the template to use * portal_template: // allow the choice of portal template (0 = default) - * email_template: // allow the choice of email template (0 = default) - * + * email_template: // allow the choice of email template (0 = default) + * * invoice_frequency: // invoicing pro only (0 = once only, 1 = week, 2 = month, 3 = year) - * + * * invoice_number: // this is over-ridable in settings - * invoice_date: // date of the invoice + * invoice_date: // date of the invoice * invoice_due: // when due -1 (no due date), 0 (on receipt), 10, 15, 30, 45, 60, 90 (days in advance of invoice date) - * - *! invoice_ref: // internal reference number - * + * + * ! invoice_ref: // internal reference number + * * invoice_parent: // invoice pro only (0 for parent), id of parent if child - * + * * invoice_pay_via: // 0 online, 1 bank transfer, 2 (both) - Zak addition to show online payment only for some - * - * - *! invoice_logo_url: // url of the invoice logo (default, or custom per invoice) + * + * + * ! invoice_logo_url: // url of the invoice logo (default, or custom per invoice) * invoice_business_details: // the details from settings to go on the invoice (also in settings obj) - * - * + * + * * invoice_send_to: // email to send the invoice to - *! invoice_contact: // 0 or contact ID - *! invoice_company: // 0 or company ID + * ! invoice_contact: // 0 or contact ID + * ! invoice_company: // 0 or company ID * invoice_address_to: // 0 contact or 1 company. So if assigned to Mike, can be address to a company (i.e. Mike Stott: Jetpack CRM, Mike Stott: Epic Plugins) etc - * - * + * + * * invoice_hours_or_quantity: 0 for hours, 1 for quantity - * + * * invoice_items: { * item_id: (line_item ID) - * order: (order in list, i.e. 0,1,2,3,4,5) - * title: - * description: - * unit: - * price: + * order: (order in list, i.e. 0,1,2,3,4,5) + * title: + * description: + * unit: + * price: * tax_ids: { * id: 1, rate: 20, * id: 2, rate: 19 * }, - * + * * },{ - * + * * } - * + * * invoice_discount: 0, * invoice_shipping: 0, * invoice_shipping_tax: { @@ -4448,47 +4549,44 @@ function zeroBSCRM_quotes_getFromHash($hash = ''){ * id: 2, rate: 19 * } * }, - * + * * invoice_tip: 0, 1 (allow tip) - not in UI yet * invoice_partial: 0, 1 (allow partial payment) - in UI already (i.e. can assign multiple transactions) need to handle it via checkout (i.e. pay full amount, or pay instalments) - * + * * transactions: { //the transactions against the invoice (array to allow for partial payments) * transaction_id: 5, * amount: 200, - * status: paid, + * status: paid, * }, * invoice_attachments: { * id: 1, * url: uploaded_url - * send: 0,1 + * send: 0,1 * }, * invoice_custom_fields: { - * id: 1, + * id: 1, * label: "vesting period", * type: "date", * value: "20/10/2019" * }, * //what the invoice settings are (biz info, tax etc) * settings: { - * + * * } - * + * * } - * - * + * + * * tax_linesObj = { - * id: + * id: * name: (e.g. VAT, GST) * rate: (%) - * } + * } */ - - // this gets the data (from the current DAL and outputs it to the UI) - can get via jQuery - // once happy it works and fills the current databse. This will need switching over come - // the new DAL database structure but allows me to work with the UI now ahead of time. - - + // this gets the data (from the current DAL and outputs it to the UI) - can get via jQuery + // once happy it works and fills the current databse. This will need switching over come + // the new DAL database structure but allows me to work with the UI now ahead of time. // wh Centralised, is ultimately output via ajax zeroBSCRM_AJAX_getInvoice function in Control.Invoices // was called zeroBSCRM_getInvoiceData -> zeroBSCRM_invoicing_getInvoiceData @@ -4504,32 +4602,34 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { // build response $data['invoiceObj'] = array(); - $invoice = $zbs->DAL->invoices->getInvoice( $invID, array( + $invoice = $zbs->DAL->invoices->getInvoice( + $invID, + array( - // if these two passed, will search based on these - 'idOverride' => false, // direcetly checks 1:1 match id_override - 'searchPhrase' => false, // more generic, searches id_override (reference) (and not lineitems (toadd?)) + // if these two passed, will search based on these + 'idOverride' => false, // direcetly checks 1:1 match id_override + 'searchPhrase' => false, // more generic, searches id_override (reference) (and not lineitems (toadd?)) - 'externalSource' => false, - 'externalSourceUID' => false, + 'externalSource' => false, + 'externalSourceUID' => false, - // with what? - 'withLineItems' => true, - 'withCustomFields' => true, - 'withTransactions' => true, // gets trans associated with inv as well - 'withAssigned' => true, // return ['contact'] & ['company'] objs if has link - 'withTags' => true, - 'withOwner' => true, + // with what? + 'withLineItems' => true, + 'withCustomFields' => true, + 'withTransactions' => true, // gets trans associated with inv as well + 'withAssigned' => true, // return ['contact'] & ['company'] objs if has link + 'withTags' => true, + 'withOwner' => true, - // returns scalar ID of line - 'onlyID' => false, + // returns scalar ID of line + 'onlyID' => false, - 'fields' => false // false = *, array = fieldnames - - )); + 'fields' => false, // false = *, array = fieldnames + ) + ); - if ( !is_array( $invoice ) ) { + if ( ! is_array( $invoice ) ) { // get blank defaults - this is for a de-headed serpent? (don't think should ever exist) $data['invoiceObj'] = zeroBSCRM_get_invoice_defaults( $invID ); @@ -4541,10 +4641,10 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { // ... wh done best to leave only necessary here: $now = time(); - $invoice_date_uts = isset( $invoice['date_date'] ) ? $invoice['date'] : $now; + $invoice_date_uts = isset( $invoice['date_date'] ) ? $invoice['date'] : $now; $invoice['date_date'] = jpcrm_uts_to_date_str( $invoice_date_uts, 'Y-m-d' ); - $invoice_due_date_uts = isset( $invoice['due_date'] ) ? $invoice['due_date'] : $now; + $invoice_due_date_uts = isset( $invoice['due_date'] ) ? $invoice['due_date'] : $now; $invoice['due_date_date'] = jpcrm_uts_to_date_str( $invoice_due_date_uts, 'Y-m-d' ); // this should load it all anyhow :) (DAL3+) @@ -4554,7 +4654,7 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { $settings = zeroBSCRM_get_invoice_settings(); // catch any empty shiz? seems to be what was happening. - if ( !isset( $data['invoiceObj']['invoice_logo_url'] ) ) { + if ( ! isset( $data['invoiceObj']['invoice_logo_url'] ) ) { $data['invoiceObj']['invoice_logo_url'] = $settings['logo']; } @@ -4571,7 +4671,7 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { // these should probs use $invoice['contact'] etc. leaving for now for time. $billing_email = ''; - $billing_name = ''; + $billing_name = ''; if ( isset( $data['invoiceObj']['invoice_contact'] ) && is_array( $data['invoiceObj']['invoice_contact'] ) && isset( $data['invoiceObj']['invoice_contact']['id'] ) ) { if ( isset( $data['invoiceObj']['invoice_contact']['email'] ) ) { @@ -4583,7 +4683,6 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { if ( empty( $billing_name ) ) { $billing_name = $zbs->DAL->contacts->getContactNameWithFallback( $data['invoiceObj']['invoice_contact']['id'] ); } - } elseif ( isset( $data['invoiceObj']['invoice_company'] ) && is_array( $data['invoiceObj']['invoice_company'] ) && isset( $data['invoiceObj']['invoice_company']['id'] ) ) { if ( isset( $data['invoiceObj']['invoice_company']['email'] ) ) { @@ -4592,13 +4691,12 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { if ( isset( $data['invoiceObj']['invoice_company']['name'] ) ) { $billing_name = $data['invoiceObj']['invoice_company']['name']; } - } $data['invoiceObj']['bill'] = $billing_email; - //add billing name here + // add billing name here $data['invoiceObj']['bill_name'] = $billing_name; - //handle if due is not set + // handle if due is not set $data['invoiceObj']['due'] = -1; // default if ( isset( $invoice['due'] ) ) { $data['invoiceObj']['due'] = $invoice['due']; @@ -4607,7 +4705,7 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { $data['invoiceObj']['invoice_items'] = $invoice['lineitems']; // needs translating - $hoursOrQuantity = (int) $invoice['hours_or_quantity']; // 0 = hours, 1 = quantity + $hoursOrQuantity = (int) $invoice['hours_or_quantity']; // 0 = hours, 1 = quantity $hoursOrQuantityStr = 'hours'; if ( $hoursOrQuantity > 0 ) { $hoursOrQuantityStr = 'quantity'; @@ -4615,7 +4713,7 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { $data['invoiceObj']['invoice_hours_or_quantity'] = $hoursOrQuantityStr; // are PDF engine and Client Portal installed? - $data['invoiceObj']['pdf_installed'] = zeroBSCRM_isExtensionInstalled( 'pdfinv' ); + $data['invoiceObj']['pdf_installed'] = zeroBSCRM_isExtensionInstalled( 'pdfinv' ); $data['invoiceObj']['portal_installed'] = zeroBSCRM_isExtensionInstalled( 'portal' ); // if we have Client Portal installed, build URLS @@ -4625,7 +4723,7 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { // Retrieve invoice endpoint & portal root URL $invoice_endpoint = $zbs->modules->portal->get_endpoint( ZBS_TYPE_INVOICE ); - $portalLink = zeroBS_portal_link(); + $portalLink = zeroBS_portal_link(); if ( ! str_ends_with( $portalLink, '/' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $portalLink .= '/'; } @@ -4636,7 +4734,6 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { } else { $preview_link = esc_url( $portalLink . $invoice_endpoint . '/' . $invID ); } - } // if a hash is set (or admin) load the invoice for logged out users, if agreed @@ -4652,14 +4749,14 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { $data['invoiceObj']['settings'] = $settings; // WH shim - converts DAL3 single record attrs into an array as MS expects? - $data['invoiceObj']['totals'] = array(); + $data['invoiceObj']['totals'] = array(); $data['invoiceObj']['totals']['invoice_discount_total'] = $invoice['discount']; - $data['invoiceObj']['totals']['invoice_discount_type'] = $invoice['discount_type']; - $data['invoiceObj']['totals']['invoice_postage_total'] = $invoice['shipping']; - $data['invoiceObj']['totals']['tax'] = $invoice['tax']; + $data['invoiceObj']['totals']['invoice_discount_type'] = $invoice['discount_type']; + $data['invoiceObj']['totals']['invoice_postage_total'] = $invoice['shipping']; + $data['invoiceObj']['totals']['tax'] = $invoice['tax']; // shipping total needs to return 0 in some cases if not set it is empty. GRR @ mike DB1.0 data. - if ( !array_key_exists( 'invoice_postage_total', $data['invoiceObj']['totals'] ) ) { + if ( ! array_key_exists( 'invoice_postage_total', $data['invoiceObj']['totals'] ) ) { $data['invoiceObj']['totals']['invoice_postage_total'] = 0; } @@ -4678,436 +4775,422 @@ function zeroBSCRM_invoicing_getInvoiceData( $invID = -1 ) { return false; } +/* +====================================================== + / Invoice 3.0 helpers + ====================================================== */ - /* ====================================================== - / Invoice 3.0 helpers - ====================================================== */ - - - #} General function to check the amount due on an invoice, if <= mark as paid. - // Adapted to work V3.0+ - // ... ultimately just uses zeroBSCRM_invoicing_invOutstandingBalance to check for balance + marks if paid off - function zeroBSCRM_check_amount_due_mark_paid($invoice_id=-1){ - - if ($invoice_id > 0){ - - global $zbs; +#} General function to check the amount due on an invoice, if <= mark as paid. +// Adapted to work V3.0+ +// ... ultimately just uses zeroBSCRM_invoicing_invOutstandingBalance to check for balance + marks if paid off +function zeroBSCRM_check_amount_due_mark_paid( $invoice_id = -1 ) { - $outstandingBalance = $zbs->DAL->invoices->getOutstandingBalance($invoice_id); + if ( $invoice_id > 0 ) { - // got balance? - if ($outstandingBalance <= 0 && $outstandingBalance !== false){ + global $zbs; - // mark invoice as paid - $status_str = 'Paid'; - $invoice_update = $zbs->DAL->invoices->setInvoiceStatus( $invoice_id, $status_str ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + $outstandingBalance = $zbs->DAL->invoices->getOutstandingBalance( $invoice_id ); - return $invoice_update; + // got balance? + if ( $outstandingBalance <= 0 && $outstandingBalance !== false ) { - } + // mark invoice as paid + $status_str = 'Paid'; + $invoice_update = $zbs->DAL->invoices->setInvoiceStatus( $invoice_id, $status_str ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - } + return $invoice_update; - return false; + } } -/* ====================================================== - / Invoice helpers - ====================================================== */ - - - - - -/* ====================================================== - Transactions helpers - ====================================================== */ - - // Please use direct dal calls in future work. - function zeroBS_getTransaction($tID=-1){ - - if ($tID !== -1){ - - /* - return array( - 'id'=>$tID, - 'meta'=>get_post_meta($tID, 'zbs_transaction_meta', true), - 'customerid'=>get_post_meta($tID, 'zbs_parent_cust', true), - 'companyid'=>get_post_meta($tID, 'zbs_parent_co', true) - ); - */ - - global $zbs; - - return $zbs->DAL->transactions->getTransaction($tID); - - } else return false; - - } - - - - // Please use direct dal calls in future work. - function zeroBS_getTransactions( - - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false, - $searchPhrase='', - $hasTagIDs=array(), - $inArray=array(), - $sortByField='', - $sortOrder='DESC', - $withTags=false, - $quickFilters=array(), - $external_source_uid = false - ){ - - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; + return false; +} - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; +/* +====================================================== + / Invoice helpers + ====================================================== */ - // make ARGS - $args = array( +/* +====================================================== + Transactions helpers + ====================================================== */ - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArray, - 'isTagged' => $hasTagIDs, - 'quickFilters' => $quickFilters, +// Please use direct dal calls in future work. +function zeroBS_getTransaction( $tID = -1 ) { - 'withAssigned' => $withCustomerDeets, - 'withTags' => $withTags, + if ( $tID !== -1 ) { - 'sortByField' => $sortByField, - 'sortOrder' => $sortOrder, - 'page' => $actualPage, - 'perPage' => $perPage, + /* + return array( + 'id'=>$tID, + 'meta'=>get_post_meta($tID, 'zbs_transaction_meta', true), + 'customerid'=>get_post_meta($tID, 'zbs_parent_cust', true), + 'companyid'=>get_post_meta($tID, 'zbs_parent_co', true) + ); + */ - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION), + global $zbs; - 'external_source_uid' => $external_source_uid + return $zbs->DAL->transactions->getTransaction( $tID ); + } else { + return false; + } +} - ); +// Please use direct dal calls in future work. +function zeroBS_getTransactions( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false, + $searchPhrase = '', + $hasTagIDs = array(), + $inArray = array(), + $sortByField = '', + $sortOrder = 'DESC', + $withTags = false, + $quickFilters = array(), + $external_source_uid = false +) { - return $zbs->DAL->transactions->getTransactions($args); + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; } - - // Please use direct dal calls in future work. - function zeroBS_getTransactionsCountIncParams( - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false, - $searchPhrase='', - $hasTagIDs=array(), - $inArray=array(), - $sortByField='', - $sortOrder='DESC', - $withTags=false, - $quickFilters=array() + // make ARGS + $args = array( - ){ + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArray, + 'isTagged' => $hasTagIDs, + 'quickFilters' => $quickFilters, - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; + 'withAssigned' => $withCustomerDeets, + 'withTags' => $withTags, - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + 'sortByField' => $sortByField, + 'sortOrder' => $sortOrder, + 'page' => $actualPage, + 'perPage' => $perPage, - // make ARGS - $args = array( + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArray, - 'isTagged' => $hasTagIDs, - 'quickFilters' => $quickFilters, + 'external_source_uid' => $external_source_uid, - // just count thx - 'count' => true, - 'withAssigned' => false, - - //'sortByField' => $sortByField, - //'sortOrder' => $sortOrder, - 'page' => -1, - 'perPage' => -1, - - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION) + ); + return $zbs->DAL->transactions->getTransactions( $args ); +} - ); +// Please use direct dal calls in future work. +function zeroBS_getTransactionsCountIncParams( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false, + $searchPhrase = '', + $hasTagIDs = array(), + $inArray = array(), + $sortByField = '', + $sortOrder = 'DESC', + $withTags = false, + $quickFilters = array() +) { - return $zbs->DAL->transactions->getTransactions($args); + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; } - // Please use direct dal calls in future work. - function zeroBS_getTransactionsForCustomer( - - $customerID=-1, - $withFullDetails=false, - $perPage=10, - $page=0, - $withCustomerDeets=false - - ){ - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; - - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; - - // make ARGS - $args = array( + // make ARGS + $args = array( - // Search/Filtering (leave as false to ignore) - 'assignedContact' => $customerID, + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArray, + 'isTagged' => $hasTagIDs, + 'quickFilters' => $quickFilters, - // with contact? - 'withAssigned' => $withCustomerDeets, + // just count thx + 'count' => true, + 'withAssigned' => false, - //'sortByField' => $orderBy, - //'sortOrder' => $order, - 'page' => $actualPage, - 'perPage' => $perPage, + // 'sortByField' => $sortByField, + // 'sortOrder' => $sortOrder, + 'page' => -1, + 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION) + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), + ); - ); - - return $zbs->DAL->transactions->getTransactions($args); - - } + return $zbs->DAL->transactions->getTransactions( $args ); +} // Please use direct dal calls in future work. - function zeroBS_getTransactionIDWithExternalSource($transactionExternalSource='',$transactionExternalID=''){ - - // retrieve external sources from $zbs now - global $zbs; - - #} No empties, no random externalSources :) - if (!empty($transactionExternalSource) && !empty($transactionExternalID) && array_key_exists($transactionExternalSource,$zbs->external_sources)){ - - // return id if exists - return $zbs->DAL->transactions->getTransaction(-1,array( - 'externalSource' => $transactionExternalSource, - 'externalSourceUID' => $transactionExternalID, - 'onlyID' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION) - )); - - - } - - return false; +function zeroBS_getTransactionsForCustomer( + $customerID = -1, + $withFullDetails = false, + $perPage = 10, + $page = 0, + $withCustomerDeets = false +) { + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; } + // make ARGS + $args = array( - // v3.0 + avoid using these centralised funcs (this + zeroBS_integrations_addOrUpdateTransaction) - // ... direct calls all the way :D - function zeroBS_addUpdateTransaction( - - $tID = -1, + // Search/Filtering (leave as false to ignore) + 'assignedContact' => $customerID, - /* + // with contact? + 'withAssigned' => $withCustomerDeets, - example: - $tFields = array( - - REQUIRED: - 'orderid' => 'UNIQUEID', - 'customer' => CustomerID, - 'status' => 'Completed', 'Refunded' similar. - 'total' => 123.99, + // 'sortByField' => $orderBy, + // 'sortOrder' => $order, + 'page' => $actualPage, + 'perPage' => $perPage, - RECOMMENDED: - 'date' => 12345TIME, - 'currency' => 'USD', - 'item' => 'TITLE', - 'net' => 0, - 'tax' => 0, - 'fee' => 0, - 'discount' => 0, - 'tax_rate' => 0, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), + ); - ); - - */ + return $zbs->DAL->transactions->getTransactions( $args ); +} - $tFields = array(), + // Please use direct dal calls in future work. +function zeroBS_getTransactionIDWithExternalSource( $transactionExternalSource = '', $transactionExternalID = '' ) { - $transactionExternalSource='', - $transactionExternalID='', - $transactionDate='', - $transactionTags=array(), /* extra */ + // retrieve external sources from $zbs now + global $zbs; - $fallBackLog = false, - $extraMeta = false, - $automatorPassthrough = false, + #} No empties, no random externalSources :) + if ( ! empty( $transactionExternalSource ) && ! empty( $transactionExternalID ) && array_key_exists( $transactionExternalSource, $zbs->external_sources ) ) { + + // return id if exists + return $zbs->DAL->transactions->getTransaction( + -1, + array( + 'externalSource' => $transactionExternalSource, + 'externalSourceUID' => $transactionExternalID, + 'onlyID' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), + ) + ); - $arrBuilderPrefix = 'zbst_' + } - ){ + return false; +} - - // zeroBSCRM_DEPRECATEDMSG('ZBS Function Deprecated in v3.0+. zeroBS_addUpdateTransaction should now be replaced with proper zbs->DAL->calls'); +/** + * Adds or updates a transaction. + * + * Deprecated in v3.0+ — avoid using these centralised funcs, use direct DAL calls instead. + * + * @param int $tID Transaction ID. + * @param array $tFields Transaction fields array. Required keys: 'orderid', 'customer', + * 'status', 'total'. Recommended keys: 'date', 'currency', 'item', + * 'net', 'tax', 'fee', 'discount', 'tax_rate'. + * @param string $transactionExternalSource External source identifier. + * @param string $transactionExternalID External ID. + * @param string $transactionDate Transaction date. + * @param array $transactionTags Transaction tags. + * @param bool $fallBackLog Whether to create a fallback log. + * @param bool $extraMeta Extra metadata. + * @param bool $automatorPassthrough Automator passthrough flag. + * @param string $arrBuilderPrefix Array builder prefix. + */ +function zeroBS_addUpdateTransaction( + $tID = -1, + $tFields = array(), + $transactionExternalSource = '', + $transactionExternalID = '', + $transactionDate = '', + $transactionTags = array(), + $fallBackLog = false, + $extraMeta = false, + $automatorPassthrough = false, + $arrBuilderPrefix = 'zbst_' +) { + + // zeroBSCRM_DEPRECATEDMSG('ZBS Function Deprecated in v3.0+. zeroBS_addUpdateTransaction should now be replaced with proper zbs->DAL->calls'); - global $zbs; + global $zbs; - #} Basics - /--needs unique ID, total MINIMUM - if (isset($tFields) && count($tFields) > 0){ + #} Basics - /--needs unique ID, total MINIMUM + if ( isset( $tFields ) && count( $tFields ) > 0 ) { - #} New flag - $newTrans = false; + #} New flag + $newTrans = false; - if ($tID > 0){ + if ( $tID > 0 ) { - #} Build "existing meta" to pass, (so we only update fields pushed here) - $existingMeta = $zbs->DAL->transactions->getTransaction($tID,array()); + #} Build "existing meta" to pass, (so we only update fields pushed here) + $existingMeta = $zbs->DAL->transactions->getTransaction( $tID, array() ); - // Do date comparison + update that where relevant - $originalDate = time(); - if (isset($existingMeta) && is_array($existingMeta) && isset($existingMeta['created']) && !empty($existingMeta['created'])) $originalDate = $existingMeta['created']; - if (!empty($transactionDate) && $transactionDate != ''){ + // Do date comparison + update that where relevant + $originalDate = time(); + if ( isset( $existingMeta ) && is_array( $existingMeta ) && isset( $existingMeta['created'] ) && ! empty( $existingMeta['created'] ) ) { + $originalDate = $existingMeta['created']; + } + if ( ! empty( $transactionDate ) && $transactionDate != '' ) { - #} DATE PASSED TO THE FUNCTION - $transactionDateTimestamp = strtotime($transactionDate); - #} ORIGINAL POST CREATION DATE - // no need, db2 = UTS $originalDateTimeStamp = strtotime($originalDate); - $originalDateTimeStamp = $originalDate; + #} DATE PASSED TO THE FUNCTION + $transactionDateTimestamp = strtotime( $transactionDate ); + #} ORIGINAL POST CREATION DATE + // no need, db2 = UTS $originalDateTimeStamp = strtotime($originalDate); + $originalDateTimeStamp = $originalDate; - #} Compare, if $transactionDateTimestamp < then update with passed date - if($transactionDateTimestamp < $originalDateTimeStamp){ + #} Compare, if $transactionDateTimestamp < then update with passed date + if ( $transactionDateTimestamp < $originalDateTimeStamp ) { - // straight in there :) - $zbs->DAL->transactions->addUpdateTransaction(array( - 'id' => $tID, - 'limitedFields' =>array( - array('key'=>'zbst_created','val'=>$transactionDateTimestamp,'type'=>'%d') - ))); - } - } + // straight in there :) + $zbs->DAL->transactions->addUpdateTransaction( + array( + 'id' => $tID, + 'limitedFields' => array( + array( + 'key' => 'zbst_created', + 'val' => $transactionDateTimestamp, + 'type' => '%d', + ), + ), + ) + ); + } + } + } else { - } else { + #} Set flag + $newTrans = true; - #} Set flag - $newTrans = true; + #} DATE PASSED TO THE FUNCTION + $transactionDateTimestamp = strtotime( $transactionDate ); + $tFields['created'] = $transactionDateTimestamp; - #} DATE PASSED TO THE FUNCTION - $transactionDateTimestamp = strtotime($transactionDate); - $tFields['created'] = $transactionDateTimestamp; + } - } + // this is a DAL2 legacy: + $existingMeta = array(); - // this is a DAL2 legacy: - $existingMeta = array(); + #} Build using centralised func below, passing any existing meta (updates not overwrites) + $transactionMeta = zeroBS_buildTransactionMeta( $tFields, $existingMeta, $arrBuilderPrefix ); - #} Build using centralised func below, passing any existing meta (updates not overwrites) - $transactionMeta = zeroBS_buildTransactionMeta($tFields,$existingMeta,$arrBuilderPrefix); + // format it for DAL3 addition + $args = array( - // format it for DAL3 addition - $args = array( + 'id' => $tID, + 'data' => $transactionMeta, + 'extraMeta' => $extraMeta, + 'automatorPassthrough' => $automatorPassthrough, + 'fallBackLog' => $fallBackLog, - 'id' => $tID, - 'data' => $transactionMeta, - 'extraMeta' => $extraMeta, - 'automatorPassthrough' => $automatorPassthrough, - 'fallBackLog' => $fallBackLog + ); + // few DAL2 -> DAL3 translations: - ); - // few DAL2 -> DAL3 translations: + // owner? + if ( isset( $tFields['owner'] ) > 0 ) { + $args['owner'] = $tFields['owner']; + } - // owner? - if (isset($tFields['owner']) > 0) $args['owner'] = $tFields['owner']; + // contact/companies? + if ( isset( $tFields['customer'] ) && $tFields['customer'] > 0 ) { + $args['data']['contacts'] = array( (int) $tFields['customer'] ); + } + if ( isset( $tFields['company'] ) && $tFields['company'] > 0 ) { + $args['data']['companies'] = array( (int) $tFields['company'] ); + } - // contact/companies? - if (isset($tFields['customer']) && $tFields['customer'] > 0) $args['data']['contacts'] = array((int)$tFields['customer']); - if (isset($tFields['company']) && $tFields['company'] > 0) $args['data']['companies'] = array((int)$tFields['company']); + #} Add external source/externalid + #} No empties, no random externalSources :) + $approvedExternalSource = ''; #} As this is passed to automator :) - #} Add external source/externalid - #} No empties, no random externalSources :) - $approvedExternalSource = ''; #} As this is passed to automator :) + if ( ! empty( $transactionExternalSource ) && ! empty( $transactionExternalID ) && array_key_exists( $transactionExternalSource, $zbs->external_sources ) ) { - if (!empty($transactionExternalSource) && !empty($transactionExternalID) && array_key_exists($transactionExternalSource,$zbs->external_sources)){ + #} If here, is legit. + $approvedExternalSource = $transactionExternalSource; - #} If here, is legit. - $approvedExternalSource = $transactionExternalSource; - - $extSourceArr = array( - 'source' => $approvedExternalSource, - 'uid' => $transactionExternalID - ); + $extSourceArr = array( + 'source' => $approvedExternalSource, + 'uid' => $transactionExternalID, + ); + $args['data']['externalSources'] = array( $extSourceArr ); - $args['data']['externalSources'] = array($extSourceArr); + } #} Otherwise will just be a random obj no ext source - } #} Otherwise will just be a random obj no ext source + #} For now a brutal pass through: + // wh: not sure why this was here? if (isset($tFields['trans_time']) && !empty($tFields['trans_time'])) $zbsTransactionMeta['trans_time'] = (int)$tFields['trans_time']; - #} For now a brutal pass through: - // wh: not sure why this was here? if (isset($tFields['trans_time']) && !empty($tFields['trans_time'])) $zbsTransactionMeta['trans_time'] = (int)$tFields['trans_time']; + # TAG obj (if exists) - clean etc here too + if ( isset( $transactionTags ) && is_array( $transactionTags ) ) { - # TAG obj (if exists) - clean etc here too - if (isset($transactionTags) && is_array($transactionTags)){ + $transactionTags = filter_var_array( $transactionTags, FILTER_UNSAFE_RAW ); + // Formerly this used FILTER_SANITIZE_STRING, which is now deprecated as it was fairly broken. This is basically equivalent. + // @todo Replace this with something more correct. + foreach ( $transactionTags as $k => $v ) { + $transactionTags[ $k ] = strtr( + strip_tags( $v ), + array( + "\0" => '', + '"' => '"', + "'" => ''', + '<' => '', + ) + ); + } - $transactionTags = filter_var_array($transactionTags,FILTER_UNSAFE_RAW); - // Formerly this used FILTER_SANITIZE_STRING, which is now deprecated as it was fairly broken. This is basically equivalent. - // @todo Replace this with something more correct. - foreach ( $transactionTags as $k => $v ) { - $transactionTags[$k] = strtr( - strip_tags( $v ), - array( - "\0" => '', - '"' => '"', - "'" => ''', - "<" => '', - ) - ); - } + $args['data']['tags'] = array(); + foreach ( $transactionTags as $tag_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $args['data']['tags'] = array(); - foreach ( $transactionTags as $tag_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // Check for existing tag under this name. + $tag_id = $zbs->DAL->getTag( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + -1, + array( + 'objtype' => ZBS_TYPE_TRANSACTION, + 'name' => $tag_name, + 'onlyID' => true, + ) + ); - // Check for existing tag under this name. - $tag_id = $zbs->DAL->getTag( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - -1, + // If tag doesn't exist, create one. + if ( empty( $tag_id ) ) { + $tag_id = $zbs->DAL->addUpdateTag( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase array( - 'objtype' => ZBS_TYPE_TRANSACTION, - 'name' => $tag_name, - 'onlyID' => true, + 'data' => array( + 'objtype' => ZBS_TYPE_TRANSACTION, + 'name' => $tag_name, + ), ) ); + } - // If tag doesn't exist, create one. - if ( empty( $tag_id ) ) { - $tag_id = $zbs->DAL->addUpdateTag( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - array( - 'data' => array( - 'objtype' => ZBS_TYPE_TRANSACTION, - 'name' => $tag_name, - ), - ) - ); - } - - // Add tag to list. - if ( ! empty( $tag_id ) ) { - $args['data']['tags'][] = $tag_id; - } + // Add tag to list. + if ( ! empty( $tag_id ) ) { + $args['data']['tags'][] = $tag_id; } } + } - // Update record (All IA is now fired intrinsicaly) - return $zbs->DAL->transactions->addUpdateTransaction( $args ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + // Update record (All IA is now fired intrinsicaly) + return $zbs->DAL->transactions->addUpdateTransaction( $args ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase } return false; @@ -5116,607 +5199,622 @@ function zeroBS_addUpdateTransaction( // Please use direct dal calls in future work, not this. #} Quick wrapper to future-proof. #} Should later replace all get_post_meta's with this - function zeroBS_getTransactionMeta($tID=-1){ - - global $zbs; - - // in DAL3 it's just a normal get - if (!empty($tID)) return $zbs->DAL->transactions->getTransaction($tID); +function zeroBS_getTransactionMeta( $tID = -1 ) { - return false; + global $zbs; + // in DAL3 it's just a normal get + if ( ! empty( $tID ) ) { + return $zbs->DAL->transactions->getTransaction( $tID ); } + return false; +} + // filters array for fields currently used in fields.php // v3.0+ this uses the generic zeroBS_buildObjArr, and accepts full args as per contact meta DAL2: - function zeroBS_buildTransactionMeta($arraySource=array(),$startingArray=array(),$fieldPrefix='zbst_',$outputPrefix='',$removeEmpties=false,$autoGenAutonumbers=false){ - - return zeroBS_buildObjArr($arraySource,$startingArray,$fieldPrefix,$outputPrefix,$removeEmpties,ZBS_TYPE_TRANSACTION,$autoGenAutonumbers); +function zeroBS_buildTransactionMeta( $arraySource = array(), $startingArray = array(), $fieldPrefix = 'zbst_', $outputPrefix = '', $removeEmpties = false, $autoGenAutonumbers = false ) { - } + return zeroBS_buildObjArr( $arraySource, $startingArray, $fieldPrefix, $outputPrefix, $removeEmpties, ZBS_TYPE_TRANSACTION, $autoGenAutonumbers ); +} // moves a tran from being assigned to one cust, to another // this is a fill-in to match old DAL2 func, however DAL3+ can accept customer/company, // ... so use the proper $DAL->addUpdateObjectLinks for fresh code - function zeroBSCRM_changeTransactionCustomer($id=-1,$contactID=0){ - - if (!empty($id) && $contactID > 0){ +function zeroBSCRM_changeTransactionCustomer( $id = -1, $contactID = 0 ) { - global $zbs; - return $zbs->DAL->transactions->addUpdateObjectLinks($id,array($contactID),ZBS_TYPE_CONTACT); + if ( ! empty( $id ) && $contactID > 0 ) { - } - - return false; + global $zbs; + return $zbs->DAL->transactions->addUpdateObjectLinks( $id, array( $contactID ), ZBS_TYPE_CONTACT ); } + return false; +} + // moves a tran from being assigned to one company, to another // this is a fill-in to match old DAL2 func, however DAL3+ can accept customer/company, // ... so use the proper $DAL->addUpdateObjectLinks for fresh code - function zeroBSCRM_changeTransactionCompany($id=-1,$companyID=0){ - - if (!empty($id) && $companyID > 0){ +function zeroBSCRM_changeTransactionCompany( $id = -1, $companyID = 0 ) { - global $zbs; - return $zbs->DAL->transactions->addUpdateObjectLinks($id,array($companyID),ZBS_TYPE_COMPANY); + if ( ! empty( $id ) && $companyID > 0 ) { - } - - return false; + global $zbs; + return $zbs->DAL->transactions->addUpdateObjectLinks( $id, array( $companyID ), ZBS_TYPE_COMPANY ); } + return false; +} -/* ====================================================== - / Transactions helpers - ====================================================== */ +/* +====================================================== + / Transactions helpers +====================================================== */ -/* ====================================================== - Event helpers - ====================================================== */ +/* +====================================================== + Event helpers +====================================================== */ // old way of doing - also should really be "get list of events/tasks for a contact" - function zeroBSCRM_getTaskList($cID=-1){ - - $ret = array(); - - if ($cID > 0){ +function zeroBSCRM_getTaskList( $cID = -1 ) { - global $zbs; - - return $zbs->DAL->events->getEvents(array( - 'assignedContact'=>$cID, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK) - )); + $ret = array(); - /* these translated for DAL3 + if ( $cID > 0 ) { - $i = 0; - foreach($tasks as $task){ - $ret[$i]['title'] = $task->post_title; - $ret[$i]['ID'] = $task->ID; - $ret[$i]['meta'] = get_post_meta($task->ID,'zbs_event_meta',true); - $ret[$i]['actions'] = get_post_meta($task->ID,'zbs_event_actions',true); + global $zbs; - // titles moved into meta with MS new task ui, wh bringing them out here: - if (empty($task->post_title) && is_array($ret[$i]['meta']) && isset($ret[$i]['meta']['title']) && !empty($ret[$i]['meta']['title'])){ - $ret[$i]['title'] = $ret[$i]['meta']['title']; - } + return $zbs->DAL->events->getEvents( + array( + 'assignedContact' => $cID, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), + ) + ); - $i++; - }*/ + /* + these translated for DAL3 + + $i = 0; + foreach ( $tasks as $task){ + $ret[$i]['title'] = $task->post_title; + $ret[$i]['ID'] = $task->ID; + $ret[$i]['meta'] = get_post_meta($task->ID,'zbs_event_meta',true); + $ret[$i]['actions'] = get_post_meta($task->ID,'zbs_event_actions',true); + + // titles moved into meta with MS new task ui, wh bringing them out here: + if ( empty( $task->post_title) && is_array( $ret[$i]['meta']) && isset( $ret[$i]['meta']['title']) && !empty( $ret[$i]['meta']['title'])){ + $ret[$i]['title'] = $ret[$i]['meta']['title']; + } - return $ret; - } + $i++; + }*/ - return array(); + return $ret; } + return array(); +} + // adapted to DAL3 // NOTE: $withFullDetails is redundant here // NOTE: as with all dal3 translations, objs no longer have ['meta'] etc. // USE direct DAL calls in code, not this, for future proofing - function zeroBS_getEvents( - $withFullDetails=false, - $perPage=10, - $page=0, - $ownedByID=false, - $search_term='', - $sortByField='', - $sortOrder='DESC', - $hasTagIDs=array() - ){ +function zeroBS_getEvents( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $ownedByID = false, + $search_term = '', + $sortByField = '', + $sortOrder = 'DESC', + $hasTagIDs = array() +) { - global $zbs; + global $zbs; - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; + } - // make ARGS - $args = array( + // make ARGS + $args = array( - 'withAssigned' => true, - 'withOwner' => true, + 'withAssigned' => true, + 'withOwner' => true, - 'isTagged' => $hasTagIDs, + 'isTagged' => $hasTagIDs, - 'sortByField' => $sortByField, - 'sortOrder' => $sortOrder, + 'sortByField' => $sortByField, + 'sortOrder' => $sortOrder, - 'page' => $actualPage, - 'perPage' => $perPage, + 'page' => $actualPage, + 'perPage' => $perPage, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK) + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), - ); - if ($ownedByID > 0) $args['ownedBy'] = $ownedByID; - if ( !empty( $search_term ) ) $args['searchPhrase'] = $search_term; - - return $zbs->DAL->events->getEvents($args); + ); + if ( $ownedByID > 0 ) { + $args['ownedBy'] = $ownedByID; + } + if ( ! empty( $search_term ) ) { + $args['searchPhrase'] = $search_term; } + return $zbs->DAL->events->getEvents( $args ); +} + // adapted to DAL3 // NOTE: $withFullDetails is redundant here // NOTE: as with all dal3 translations, objs no longer have ['meta'] etc. // USE direct DAL calls in code, not this, for future proofing - function zeroBS_getEventsByCustomerID($cID=-1,$withFullDetails=false,$perPage=10,$page=0){ - +function zeroBS_getEventsByCustomerID( $cID = -1, $withFullDetails = false, $perPage = 10, $page = 0 ) { - global $zbs; - - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; - - // make ARGS - $args = array( - - 'assignedContact' => $cID, + global $zbs; - 'page' => $actualPage, - 'perPage' => $perPage, + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; + } - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TASK) + // make ARGS + $args = array( + 'assignedContact' => $cID, - ); + 'page' => $actualPage, + 'perPage' => $perPage, - return $zbs->DAL->events->getEvents($args); - } + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), + ); + return $zbs->DAL->events->getEvents( $args ); +} // moves an event from being assigned to one cust, to another // this is a fill-in to match old DAL2 func, however DAL3+ can accept customer/company, // ... so use the proper $DAL->addUpdateObjectLinks for fresh code - function zeroBSCRM_changeEventCustomer($id=-1,$contactID=0){ - - if (!empty($id) && $contactID > 0){ +function zeroBSCRM_changeEventCustomer( $id = -1, $contactID = 0 ) { - global $zbs; - return $zbs->DAL->events->addUpdateObjectLinks($id,array($contactID),ZBS_TYPE_CONTACT); + if ( ! empty( $id ) && $contactID > 0 ) { - } - - return false; + global $zbs; + return $zbs->DAL->events->addUpdateObjectLinks( $id, array( $contactID ), ZBS_TYPE_CONTACT ); } + return false; +} - // Add an event - function zeroBS_addUpdateEvent($eventID = -1, $eventFields = array(), $reminders=array()){ - - // if using 'from' and 'to', probably using v1 dal, so translate dates: - if (isset($eventFields['from'])) $eventFields['from'] = strtotime($eventFields['from']); - if (isset($eventFields['to'])) $eventFields['to'] = strtotime($eventFields['to']); - + // Add an event +function zeroBS_addUpdateEvent( $eventID = -1, $eventFields = array(), $reminders = array() ) { - #} Build using centralised func below, passing any existing meta (updates not overwrites) - $removeEmpties = false; - $zbsEventMeta = zeroBS_buildObjArr($eventFields,array(),'','',$removeEmpties,ZBS_TYPE_TASK); + // if using 'from' and 'to', probably using v1 dal, so translate dates: + if ( isset( $eventFields['from'] ) ) { + $eventFields['from'] = strtotime( $eventFields['from'] ); + } + if ( isset( $eventFields['to'] ) ) { + $eventFields['to'] = strtotime( $eventFields['to'] ); + } - // Some sanitation MS has added. Really, DAL isn't place to sanitize, - // ... by time it gets here it should be sanitized (e.g. a level up) - // ... leaving as I translate this to DAL3 - //$zbsEventMeta = filter_var_array($eventFields,FILTER_SANITIZE_STRING); + #} Build using centralised func below, passing any existing meta (updates not overwrites) + $removeEmpties = false; + $zbsEventMeta = zeroBS_buildObjArr( $eventFields, array(), '', '', $removeEmpties, ZBS_TYPE_TASK ); + // Some sanitation MS has added. Really, DAL isn't place to sanitize, + // ... by time it gets here it should be sanitized (e.g. a level up) + // ... leaving as I translate this to DAL3 + // $zbsEventMeta = filter_var_array($eventFields,FILTER_SANITIZE_STRING); - // format it for DAL3 addition - $args = array( + // format it for DAL3 addition + $args = array( - 'data' => $zbsEventMeta + 'data' => $zbsEventMeta, - ); + ); - global $zbs; + global $zbs; - // few DAL2 -> DAL3 translations: + // few DAL2 -> DAL3 translations: - // owner? - if (isset($eventFields['owner']) > 0) $args['owner'] = $eventFields['owner']; + // owner? + if ( isset( $eventFields['owner'] ) > 0 ) { + $args['owner'] = $eventFields['owner']; + } - // contact/companies? - if (isset($eventFields['customer']) && $eventFields['customer'] > 0) $args['data']['contacts'] = array($eventFields['customer']); - if (isset($eventFields['company']) && $eventFields['company'] > 0) $args['data']['companies'] = array($eventFields['company']); + // contact/companies? + if ( isset( $eventFields['customer'] ) && $eventFields['customer'] > 0 ) { + $args['data']['contacts'] = array( $eventFields['customer'] ); + } + if ( isset( $eventFields['company'] ) && $eventFields['company'] > 0 ) { + $args['data']['companies'] = array( $eventFields['company'] ); + } - $args['data']['reminders'] = array(); + $args['data']['reminders'] = array(); - // reminders into new DAL2 eventreminder format: - if (is_array($reminders) && count($reminders) > 0) foreach ($reminders as $reminder){ + // reminders into new DAL2 eventreminder format: + if ( is_array( $reminders ) && count( $reminders ) > 0 ) { + foreach ( $reminders as $reminder ) { // this just adds with correct fields $args['data']['reminders'][] = array( - 'event' => (int)$eventID, - 'remind_at' => (int)$reminder['remind_at'], // just assume is int - garbage in, garbage out ($reminder['remind_at']) ? $reminder['remind_at'] : false; // if int, this - 'sent' => (isset($reminder['sent']) && $reminder['sent'] > 0) ? $reminder['sent'] : -1 + 'event' => (int) $eventID, + 'remind_at' => (int) $reminder['remind_at'], // just assume is int - garbage in, garbage out ($reminder['remind_at']) ? $reminder['remind_at'] : false; // if int, this + 'sent' => ( isset( $reminder['sent'] ) && $reminder['sent'] > 0 ) ? $reminder['sent'] : -1, ); } - - // updating.... - if ($eventID > 0) $args['id'] = (int)$eventID; - - // simples - return $zbs->DAL->events->addUpdateEvent($args); - } -/* ====================================================== - / Event helpers - ====================================================== */ - -/* ====================================================== - Form helpers - ====================================================== */ - - // Please use direct dal calls in future work. - // simple wrapper for Form - function zeroBS_getForm($formID=-1){ - - if ($formID > 0){ - - /* - return array( - 'id'=>$fID, - - // mikes init fields - 'meta'=>get_post_meta($fID,'zbs_form_field_meta',true), - 'style'=>get_post_meta($fID, 'zbs_form_style', true), - 'views'=>get_post_meta($fID, 'zbs_form_views', true), - 'conversions'=>get_post_meta($fID, 'zbs_form_conversions', true) - - ); - */ - - global $zbs; - - return $zbs->DAL->forms->getForm($formID); - - } - - return false; + // updating.... + if ( $eventID > 0 ) { + $args['id'] = (int) $eventID; } + // simples + return $zbs->DAL->events->addUpdateEvent( $args ); +} - // Please use direct dal calls in future work. - function zeroBS_getForms( - - $withFullDetails=false, - $perPage=10, - $page=0, - $searchPhrase='', - $inArray=array(), - $sortByField='', - $sortOrder='DESC', - $quickFilters=array(), - $hasTagIDs=array() - - ){ - - // quickFilters not used for forms :) *yet - - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; +/* +====================================================== + / Event helpers + ====================================================== */ - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; +/* +====================================================== + Form helpers + ====================================================== */ - // make ARGS - $args = array( + // Please use direct dal calls in future work. + // simple wrapper for Form +function zeroBS_getForm( $formID = -1 ) { - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArray, - 'isTagged' => $hasTagIDs, + if ( $formID > 0 ) { - 'sortByField' => $sortByField, - 'sortOrder' => $sortOrder, - 'page' => $actualPage, - 'perPage' => $perPage, + /* + return array( + 'id'=>$fID, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_FORM) + // mikes init fields + 'meta'=>get_post_meta($fID,'zbs_form_field_meta',true), + 'style'=>get_post_meta($fID, 'zbs_form_style', true), + 'views'=>get_post_meta($fID, 'zbs_form_views', true), + 'conversions'=>get_post_meta($fID, 'zbs_form_conversions', true) + ); + */ - ); + global $zbs; - return $zbs->DAL->forms->getForms($args); + return $zbs->DAL->forms->getForm( $formID ); } - // Please use direct dal calls in future work. - function zeroBS_getFormsCountIncParams( - - $withFullDetails=false, - $perPage=10, - $page=0, - $searchPhrase='', - $inArray=array(), - $sortByField='', - $sortOrder='DESC', - $quickFilters=array(), - $hasTagIDs=array() - - ){ + return false; +} - // quickFilters not used for forms :) *yet + // Please use direct dal calls in future work. +function zeroBS_getForms( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $searchPhrase = '', + $inArray = array(), + $sortByField = '', + $sortOrder = 'DESC', + $quickFilters = array(), + $hasTagIDs = array() +) { + + // quickFilters not used for forms :) *yet - // $withFullDetails = irrelevant with new DB2 (always returns) - global $zbs; + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; - $actualPage = $page; - if ($actualPage < 0) $actualPage = 0; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; + } - // make ARGS - $args = array( + // make ARGS + $args = array( - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => $searchPhrase, - 'inArr' => $inArray, - 'isTagged' => $hasTagIDs, + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArray, + 'isTagged' => $hasTagIDs, - // just count thx - 'count' => true, + 'sortByField' => $sortByField, + 'sortOrder' => $sortOrder, + 'page' => $actualPage, + 'perPage' => $perPage, - 'page' => -1, - 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_FORM ), - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_FORM) + ); + return $zbs->DAL->forms->getForms( $args ); +} - ); + // Please use direct dal calls in future work. +function zeroBS_getFormsCountIncParams( + $withFullDetails = false, + $perPage = 10, + $page = 0, + $searchPhrase = '', + $inArray = array(), + $sortByField = '', + $sortOrder = 'DESC', + $quickFilters = array(), + $hasTagIDs = array() +) { + + // quickFilters not used for forms :) *yet - return $zbs->DAL->forms->getForms($args); + // $withFullDetails = irrelevant with new DB2 (always returns) + global $zbs; + $actualPage = $page; + if ( $actualPage < 0 ) { + $actualPage = 0; } + // make ARGS + $args = array( + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => $searchPhrase, + 'inArr' => $inArray, + 'isTagged' => $hasTagIDs, + // just count thx + 'count' => true, -/* ====================================================== - / Form helpers - ====================================================== */ + 'page' => -1, + 'perPage' => -1, -/* ====================================================== - Settings helpers - ====================================================== */ + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_FORM ), - #} Minified get setting func - function zeroBSCRM_getSetting($key,$freshFromDB=false){ + ); + + return $zbs->DAL->forms->getForms( $args ); +} - global $zbs; - $zbs->checkSettingsSetup(); - return $zbs->settings->get($key,$freshFromDB); +/* +====================================================== + / Form helpers +====================================================== */ - } +/* +====================================================== + Settings helpers +====================================================== */ -/* ====================================================== - / Settings helpers - ====================================================== */ + #} Minified get setting func +function zeroBSCRM_getSetting( $key, $freshFromDB = false ) { + global $zbs; + $zbs->checkSettingsSetup(); + return $zbs->settings->get( $key, $freshFromDB ); +} +/* +====================================================== + / Settings helpers +====================================================== */ -/* ====================================================== - Alias / AKA helpers - ====================================================== */ +/* +====================================================== + Alias / AKA helpers +====================================================== */ // Aliases - direct SQL here, could do with moving to DAL3 - #} (Generic) See if already in use/exists - function zeroBS_canUseAlias($objType=ZBS_TYPE_CONTACT,$alias=''){ +function zeroBS_canUseAlias( $objType = ZBS_TYPE_CONTACT, $alias = '' ) { - if (!empty($alias)) { + if ( ! empty( $alias ) ) { // verify email? - if (!zeroBSCRM_validateEmail($alias)) return false; + if ( ! zeroBSCRM_validateEmail( $alias ) ) { + return false; + } // is in use? - // is customer with this email? - $existing = zeroBS_getCustomerIDWithEmail($alias); - - if (!empty($existing)) return false; + // is customer with this email? + $existing = zeroBS_getCustomerIDWithEmail( $alias ); - global $wpdb,$ZBSCRM_t; - - $query = $wpdb->prepare( "SELECT ID FROM ".$ZBSCRM_t['aka']." WHERE aka_type = %d AND aka_alias = %s", $objType, $alias); + if ( ! empty( $existing ) ) { + return false; + } - $aliasID = $wpdb->get_var($query); + global $wpdb, $ZBSCRM_t; - // has alias in there already? - if (!empty($aliasID)) return false; + $query = $wpdb->prepare( 'SELECT ID FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = %d AND aka_alias = %s', $objType, $alias ); - // usable - return true; + $aliasID = $wpdb->get_var( $query ); + // has alias in there already? + if ( ! empty( $aliasID ) ) { + return false; } - return false; + // usable + return true; + } - #} Get specific alias if exists - function zeroBS_getObjAlias($objType=ZBS_TYPE_CONTACT,$objID=-1,$alias=''){ + return false; +} - if (!empty($objID) && !empty($alias)) { + #} Get specific alias if exists +function zeroBS_getObjAlias( $objType = ZBS_TYPE_CONTACT, $objID = -1, $alias = '' ) { - global $wpdb,$ZBSCRM_t; + if ( ! empty( $objID ) && ! empty( $alias ) ) { - $query = $wpdb->prepare( "SELECT ID,aka_alias,aka_created,aka_lastupdated FROM ".$ZBSCRM_t['aka']." WHERE aka_type = %d AND aka_id = %d AND aka_alias = %s", $objType, $objID, $alias); + global $wpdb, $ZBSCRM_t; - $alias = $wpdb->get_row($query, ARRAY_A); + $query = $wpdb->prepare( 'SELECT ID,aka_alias,aka_created,aka_lastupdated FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = %d AND aka_id = %d AND aka_alias = %s', $objType, $objID, $alias ); - // check it + return - if (is_array($alias)) return $alias; + $alias = $wpdb->get_row( $query, ARRAY_A ); + // check it + return + if ( is_array( $alias ) ) { + return $alias; } - - return false; } - #} Get specific alias if exists - function zeroBS_getAliasByID($objType=ZBS_TYPE_CONTACT,$objID=-1,$aliasID=-1){ + return false; +} - if (!empty($objID) && !empty($aliasID)) { + #} Get specific alias if exists +function zeroBS_getAliasByID( $objType = ZBS_TYPE_CONTACT, $objID = -1, $aliasID = -1 ) { - global $wpdb,$ZBSCRM_t; + if ( ! empty( $objID ) && ! empty( $aliasID ) ) { - $query = $wpdb->prepare( "SELECT ID,aka_alias,aka_created,aka_lastupdated FROM ".$ZBSCRM_t['aka']." WHERE aka_type = %d AND aka_id = %d AND ID = %d", $objType, $objID, $aliasID); + global $wpdb, $ZBSCRM_t; - $alias = $wpdb->get_row($query, ARRAY_A); + $query = $wpdb->prepare( 'SELECT ID,aka_alias,aka_created,aka_lastupdated FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = %d AND aka_id = %d AND ID = %d', $objType, $objID, $aliasID ); - // check it + return - if (is_array($alias)) return $alias; + $alias = $wpdb->get_row( $query, ARRAY_A ); + // check it + return + if ( is_array( $alias ) ) { + return $alias; } - - return false; } + return false; +} + #} Get All Aliases against an obj. - function zeroBS_getObjAliases($objType=ZBS_TYPE_CONTACT,$objID=-1){ +function zeroBS_getObjAliases( $objType = ZBS_TYPE_CONTACT, $objID = -1 ) { - if (!empty($objID)) { + if ( ! empty( $objID ) ) { - global $wpdb,$ZBSCRM_t; + global $wpdb, $ZBSCRM_t; - $query = $wpdb->prepare( "SELECT ID,aka_alias,aka_created,aka_lastupdated FROM ".$ZBSCRM_t['aka']." WHERE aka_type = %d AND aka_id = %d", $objType, $objID ); - - $aliases = $wpdb->get_results($query, ARRAY_A); + $query = $wpdb->prepare( 'SELECT ID,aka_alias,aka_created,aka_lastupdated FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = %d AND aka_id = %d', $objType, $objID ); - // check it + return - if (is_array($aliases) && count($aliases) > 0) return $aliases; + $aliases = $wpdb->get_results( $query, ARRAY_A ); + // check it + return + if ( is_array( $aliases ) && count( $aliases ) > 0 ) { + return $aliases; } - - return false; } - #} add Aliases to an obj. - function zeroBS_addObjAlias($objType=ZBS_TYPE_CONTACT,$objID=-1,$alias=''){ + return false; +} - if (!empty($objID) && !empty($alias)) { +#} add Aliases to an obj. +function zeroBS_addObjAlias( $objType = ZBS_TYPE_CONTACT, $objID = -1, $alias = '' ) { - // check not already there - $existing = zeroBS_getObjAlias($objType,$objID,$alias); - if (!is_array($existing)){ + if ( ! empty( $objID ) && ! empty( $alias ) ) { - // insert + // check not already there + $existing = zeroBS_getObjAlias( $objType, $objID, $alias ); + if ( ! is_array( $existing ) ) { - global $wpdb,$ZBSCRM_t; + // insert - if ($wpdb->insert( - $ZBSCRM_t['aka'], - array( - 'aka_type' => $objType, - 'aka_id' => $objID , - 'aka_alias' => $alias , - 'aka_created' => time() , - 'aka_lastupdated' => time() - ), - array( - '%d', - '%d' , - '%s' , - '%d' , - '%d' - ) - )){ + global $wpdb, $ZBSCRM_t; - // success - return $wpdb->insert_id; + if ( $wpdb->insert( + $ZBSCRM_t['aka'], + array( + 'aka_type' => $objType, + 'aka_id' => $objID, + 'aka_alias' => $alias, + 'aka_created' => time(), + 'aka_lastupdated' => time(), + ), + array( + '%d', + '%d', + '%s', + '%d', + '%d', + ) + ) ) { - } else { - return false; - } + // success + return $wpdb->insert_id; } else { - - // return true, already exists - return true; - + return false; } + } else { - } + // return true, already exists + return true; - return false; + } } - #} remove Alias from an obj. - function zeroBS_removeObjAlias($objType=ZBS_TYPE_CONTACT,$objID=-1,$alias=''){ + return false; +} + +#} remove Alias from an obj. +function zeroBS_removeObjAlias( $objType = ZBS_TYPE_CONTACT, $objID = -1, $alias = '' ) { - if (!empty($objID) && !empty($alias)) { + if ( ! empty( $objID ) && ! empty( $alias ) ) { - // check there/find ID - $existing = zeroBS_getObjAlias($objType,$objID,$alias); + // check there/find ID + $existing = zeroBS_getObjAlias( $objType, $objID, $alias ); - if (is_array($existing)){ + if ( is_array( $existing ) ) { - // just brutal :) + // just brutal :) - global $wpdb,$ZBSCRM_t; - - return $wpdb->delete($ZBSCRM_t['aka'], array( 'ID' => $existing['ID'] ), array( '%d' ) ); + global $wpdb, $ZBSCRM_t; - } + return $wpdb->delete( $ZBSCRM_t['aka'], array( 'ID' => $existing['ID'] ), array( '%d' ) ); } - - return false; } - #} remove Alias from an obj. - function zeroBS_removeObjAliasByID($objType=ZBS_TYPE_CONTACT,$objID=-1,$aliasID=-1){ + return false; +} - if (!empty($objID) && !empty($aliasID)) { +#} remove Alias from an obj. +function zeroBS_removeObjAliasByID( $objType = ZBS_TYPE_CONTACT, $objID = -1, $aliasID = -1 ) { - // check there/find ID - $existing = zeroBS_getAliasByID($objType,$objID,$aliasID); + if ( ! empty( $objID ) && ! empty( $aliasID ) ) { - if (is_array($existing)){ + // check there/find ID + $existing = zeroBS_getAliasByID( $objType, $objID, $aliasID ); - // just brutal :) + if ( is_array( $existing ) ) { - global $wpdb,$ZBSCRM_t; - - return $wpdb->delete($ZBSCRM_t['aka'], array( 'ID' => $existing['ID'] ), array( '%d' ) ); + // just brutal :) - } + global $wpdb, $ZBSCRM_t; - } + return $wpdb->delete( $ZBSCRM_t['aka'], array( 'ID' => $existing['ID'] ), array( '%d' ) ); - return false; + } } -/* ====================================================== - / Alias / AKA helpers - ====================================================== */ + return false; +} +/* +====================================================== + / Alias / AKA helpers +====================================================== */ -/* ====================================================== - Value Calculator / helpers - ====================================================== */ +/* +====================================================== + Value Calculator / helpers +====================================================== */ /** * Calculates the total value associated with a contact or company entity. @@ -5742,39 +5840,43 @@ function jpcrm_get_total_value_from_contact_or_company( $entity ) { $include_invoices_in_total = true; $include_transations_in_total = true; if ( isset( $settings['jpcrm_total_value_fields'] ) ) { - $include_invoices_in_total = isset( $settings['jpcrm_total_value_fields']['invoices'] ) && $settings['jpcrm_total_value_fields']['invoices'] === 1; - $include_transations_in_total = isset( $settings['jpcrm_total_value_fields']['transactions'] ) && $settings['jpcrm_total_value_fields']['transactions'] === 1; + $include_invoices_in_total = isset( $settings['jpcrm_total_value_fields']['invoices'] ) && $settings['jpcrm_total_value_fields']['invoices'] === 1; + $include_transations_in_total = isset( $settings['jpcrm_total_value_fields']['transactions'] ) && $settings['jpcrm_total_value_fields']['transactions'] === 1; } $total_value = 0; $total_value += $include_invoices_in_total ? $invoices_total : 0; $total_value += $include_transations_in_total ? $transactions_total : 0; if ( $include_invoices_in_total && $include_transations_in_total && isset( $entity['transactions_paid_total'] ) && $entity['transactions_paid_total'] > 0 ) { - $total_value -= $entity['transactions_paid_total']; + $total_value -= $entity['transactions_paid_total']; } return $total_value; } - // evolved for dal3.0 - // left in place + translated, but FAR better to just use 'withValues' => true on a getContact call directly. + // evolved for dal3.0 + // left in place + translated, but FAR better to just use 'withValues' => true on a getContact call directly. // THIS STAYS THE SAME FOR DB2 until trans+invoices MOVED OVER #DB2ROUND2 - #} Main function to return a customers "total value" + #} Main function to return a customers "total value" #} At MVP that means Invoices + Transactions - function zeroBS_customerTotalValue($contactID='',$customerInvoices=array(),$customerTransactions=array()){ +function zeroBS_customerTotalValue( $contactID = '', $customerInvoices = array(), $customerTransactions = array() ) { - global $zbs; + global $zbs; - $contactWithVals = $zbs->DAL->contacts->getContact($contactID,array( + $contactWithVals = $zbs->DAL->contacts->getContact( + $contactID, + array( 'withCustomFields' => false, - 'withValues' => true)); - - // throwaway obj apart from totals - // later could optimise, but better to optimise 1 level up and not even use this func - if (isset($contactWithVals['total_value'])) return $contactWithVals['total_value']; - - return 0; + 'withValues' => true, + ) + ); + // throwaway obj apart from totals + // later could optimise, but better to optimise 1 level up and not even use this func + if ( isset( $contactWithVals['total_value'] ) ) { + return $contactWithVals['total_value']; } + return 0; +} /** * Adds up value of quotes for a customer... @@ -5870,257 +5972,277 @@ function zeroBS_customerTransactionsValue( $contact_id = '', $customer_transacti return 0; } -/* ====================================================== - / Value Calculator / helpers - ====================================================== */ - +/* +====================================================== + / Value Calculator / helpers +====================================================== */ // =============================================================================== // ======== Security Logs (used for Quote + Trans hashlink access) ============== // this is fired on all req (expects a "fini" followup fire of next func to mark "success") // (defaults to failed req.) - function zeroBSCRM_security_logRequest($reqType='unknown',$reqHash='',$reqID=-1){ - - // don't log requests for admins, who by nature, can see all - // needs to match zeroBSCRM_security_finiRequest precheck - if (zeroBSCRM_isZBSAdminOrAdmin()) return false; +function zeroBSCRM_security_logRequest( $reqType = 'unknown', $reqHash = '', $reqID = -1 ) { - global $wpdb,$ZBSCRM_t; - - // if user logged in, also log id - $userID = -1; $current_user = wp_get_current_user(); - if (isset($current_user->ID)) $userID = (int)$current_user->ID; - $userIP = zeroBSCRM_getRealIpAddr(); + // don't log requests for admins, who by nature, can see all + // needs to match zeroBSCRM_security_finiRequest precheck + if ( zeroBSCRM_isZBSAdminOrAdmin() ) { + return false; + } - // validate these a bit - $validTypes = array('quoteeasy','inveasy'); - if (!in_array($reqType, $validTypes)) $reqType = 'na'; - $reqHash = sanitize_text_field( $reqHash ); if (strlen($reqHash) > 128) $reqHash = ''; - $reqID = (int)sanitize_text_field( $reqID ); + global $wpdb, $ZBSCRM_t; - if ($wpdb->insert( - $ZBSCRM_t['security_log'], - array( + // if user logged in, also log id + $userID = -1; + $current_user = wp_get_current_user(); + if ( isset( $current_user->ID ) ) { + $userID = (int) $current_user->ID; + } + $userIP = zeroBSCRM_getRealIpAddr(); - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - 'zbs_owner' => -1, //zeroBSCRM_currentUserID(), + // validate these a bit + $validTypes = array( 'quoteeasy', 'inveasy' ); + if ( ! in_array( $reqType, $validTypes ) ) { + $reqType = 'na'; + } + $reqHash = sanitize_text_field( $reqHash ); + if ( strlen( $reqHash ) > 128 ) { + $reqHash = ''; + } + $reqID = (int) sanitize_text_field( $reqID ); - 'zbssl_reqtype' => $reqType, - 'zbssl_ip' => $userIP, - 'zbssl_reqhash' => $reqHash, + if ( $wpdb->insert( + $ZBSCRM_t['security_log'], + array( - 'zbssl_reqid' => $reqID, - 'zbssl_loggedin_id' => $userID, - 'zbssl_reqstatus' => -1, // guilty until proven... - 'zbssl_reqtime' => time() - ), - array( - '%d', + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + 'zbs_owner' => -1, // zeroBSCRM_currentUserID(), - '%s' , - '%s' , - '%s' , + 'zbssl_reqtype' => $reqType, + 'zbssl_ip' => $userIP, + 'zbssl_reqhash' => $reqHash, - '%d' , - '%d' , - '%d' , - '%d' - ) - )){ + 'zbssl_reqid' => $reqID, + 'zbssl_loggedin_id' => $userID, + 'zbssl_reqstatus' => -1, // guilty until proven... + 'zbssl_reqtime' => time(), + ), + array( + '%d', - // success - return $wpdb->insert_id; + '%s', + '%s', + '%s', - } + '%d', + '%d', + '%d', + '%d', + ) + ) ) { - return false; + // success + return $wpdb->insert_id; } - // after security validated, - function zeroBSCRM_security_finiRequest($requestID=-1){ - - // don't log requests for admins, who by nature, can see all - // needs to match zeroBSCRM_security_logRequest precheck - if (zeroBSCRM_isZBSAdminOrAdmin()) return false; + return false; +} - // basic check - $requestID = (int)$requestID; + // after security validated, +function zeroBSCRM_security_finiRequest( $requestID = -1 ) { - if ($requestID > 0){ + // don't log requests for admins, who by nature, can see all + // needs to match zeroBSCRM_security_logRequest precheck + if ( zeroBSCRM_isZBSAdminOrAdmin() ) { + return false; + } - global $wpdb,$ZBSCRM_t; + // basic check + $requestID = (int) $requestID; - // for now just brutal update, not even comparing IP - if ($wpdb->update( - $ZBSCRM_t['security_log'], - array( - 'zbssl_reqstatus' => 1 - ), - array( // where - 'ID' => $requestID - ), - array( - '%d', - ), - array( - '%d' - ) - ) !== false){ + if ( $requestID > 0 ) { - // return id - return $requestID; + global $wpdb, $ZBSCRM_t; - } + // for now just brutal update, not even comparing IP + if ( $wpdb->update( + $ZBSCRM_t['security_log'], + array( + 'zbssl_reqstatus' => 1, + ), + array( // where + 'ID' => $requestID, + ), + array( + '%d', + ), + array( + '%d', + ) + ) !== false ) { - } + // return id + return $requestID; - return false; + } } - // checks if blocked - function zeroBSCRM_security_blockRequest($reqType='unknown'){ + return false; +} - // don't log requests for admins, who by nature, can see all - // needs to match zeroBSCRM_security_logRequest etc. above - if (zeroBSCRM_isZBSAdminOrAdmin()) return false; + // checks if blocked +function zeroBSCRM_security_blockRequest( $reqType = 'unknown' ) { - global $zbs,$wpdb,$ZBSCRM_t; + // don't log requests for admins, who by nature, can see all + // needs to match zeroBSCRM_security_logRequest etc. above + if ( zeroBSCRM_isZBSAdminOrAdmin() ) { + return false; + } - // see if more than X (5?) failed request accessed by this ip within last Y (48h?) - $userIP = zeroBSCRM_getRealIpAddr(); - $sinceTime = time()-172800; // 48h = 172800 - $maxFails = 5; - $query = $wpdb->prepare( "SELECT COUNT(ID) FROM ".$ZBSCRM_t['security_log']." WHERE zbssl_ip = %s AND zbssl_reqstatus <> %d AND zbssl_reqtime > %d", array($userIP,1,$sinceTime)); - $countFailed = (int)$wpdb->get_var($query); + global $zbs, $wpdb, $ZBSCRM_t; - // less than .. - if ($countFailed < $maxFails) return false; + // see if more than X (5?) failed request accessed by this ip within last Y (48h?) + $userIP = zeroBSCRM_getRealIpAddr(); + $sinceTime = time() - 172800; // 48h = 172800 + $maxFails = 5; + $query = $wpdb->prepare( 'SELECT COUNT(ID) FROM ' . $ZBSCRM_t['security_log'] . ' WHERE zbssl_ip = %s AND zbssl_reqstatus <> %d AND zbssl_reqtime > %d', array( $userIP, 1, $sinceTime ) ); + $countFailed = (int) $wpdb->get_var( $query ); - return true; + // less than .. + if ( $countFailed < $maxFails ) { + return false; } + return true; +} // removes all security logs older than setting (72h at addition) // this is run DAILY by a cron job in ZeroBSCRM.CRON.php - function zeroBSCRM_clearSecurityLogs(){ - - global $zbs,$wpdb,$ZBSCRM_t; +function zeroBSCRM_clearSecurityLogs() { - // older than - $deleteOlderThanTime = time()-259200; // 72h = 259200 + global $zbs, $wpdb, $ZBSCRM_t; - // delete - $wpdb->query($wpdb->prepare("DELETE FROM ".$ZBSCRM_t['security_log']." WHERE zbssl_reqtime < %d",$deleteOlderThanTime)); - - } + // older than + $deleteOlderThanTime = time() - 259200; // 72h = 259200 + // delete + $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $ZBSCRM_t['security_log'] . ' WHERE zbssl_reqtime < %d', $deleteOlderThanTime ) ); +} - function zeroBSCRM_hashes_GetHashForObj($objID = -1,$objTypeID=-1){ +function zeroBSCRM_hashes_GetHashForObj( $objID = -1, $objTypeID = -1 ) { - if ($objID > 0 && $objTypeID > 0){ + if ( $objID > 0 && $objTypeID > 0 ) { - global $zbs; - $hash = $zbs->DAL->meta($objTypeID,$objID,'zbshash',''); - - // Return with PREFIX (makes it interpretable later on as this is shared between invID + invHash (for example) at endpoint /invoices/*hashorid) - if (!empty($hash)) return 'zh-'.$hash; + global $zbs; + $hash = $zbs->DAL->meta( $objTypeID, $objID, 'zbshash', '' ); + // Return with PREFIX (makes it interpretable later on as this is shared between invID + invHash (for example) at endpoint /invoices/*hashorid) + if ( ! empty( $hash ) ) { + return 'zh-' . $hash; } - - return false; } + return false; +} - // NOTE: This is now GENERIC, for quotes/invs whatever has meta :) (DAL3+ pass objTypeID) - //function is this a hash of an INVOICE. Could be refined when DB2.0 - //function for checking if a hash is valid - // ... THIS WAS refactored for v3.0, now uses hash cols on objs :) - function zeroBSCRM_hashes_GetObjFromHash($hash = '', $pay = -1, $objTypeID=-1){ +// NOTE: This is now GENERIC, for quotes/invs whatever has meta :) (DAL3+ pass objTypeID) +// function is this a hash of an INVOICE. Could be refined when DB2.0 +// function for checking if a hash is valid +// ... THIS WAS refactored for v3.0, now uses hash cols on objs :) +function zeroBSCRM_hashes_GetObjFromHash( $hash = '', $pay = -1, $objTypeID = -1 ) { - // def - $ret = array( - 'success'=> false, - 'data'=>array() - ); + // def + $ret = array( + 'success' => false, + 'data' => array(), + ); - //SANITIZE - $hash = sanitize_text_field($hash); //sanitize it here + // SANITIZE + $hash = sanitize_text_field( $hash ); // sanitize it here // if prefix still present, chunk off if ( str_starts_with( $hash, 'zh-' ) ) { $hash = substr( $hash, 3 ); } - // get if poss - if (!empty($hash) && $objTypeID > 0){ + // get if poss + if ( ! empty( $hash ) && $objTypeID > 0 ) { - global $zbs; + global $zbs; - switch ($objTypeID){ + switch ( $objTypeID ) { - case ZBS_TYPE_INVOICE: + case ZBS_TYPE_INVOICE: + // retrieve, if any + $invoice = $zbs->DAL->invoices->getInvoice( + -1, + array( + 'hash' => $hash, + 'withAssigned' => true, + ) + ); - // retrieve, if any - $invoice = $zbs->DAL->invoices->getInvoice(-1,array('hash'=>$hash,'withAssigned'=>true)); + // got inv? + if ( is_array( $invoice ) && isset( $invoice['id'] ) ) { - // got inv? - if (is_array($invoice) && isset($invoice['id'])){ + $contactID = -1; + // return the customer information that the invoice will need (i.e. Stripe customerID) same function will be used + // in invoice checkout process (invoice pro) when being paid for using a HASH URL. - $contactID = -1; - //return the customer information that the invoice will need (i.e. Stripe customerID) same function will be used - //in invoice checkout process (invoice pro) when being paid for using a HASH URL. + if ( $pay > 0 ) { - if ($pay > 0){ - - //paying so need the customerID from settings otherwise just viewing so dont need to expose data - // WH: I've added this for future ease: - if (is_array($invoice) && isset($invoice['contact']) && is_array($invoice['contact']) && count($invoice['contact']) > 0) $contactID = $invoice['contact'][0]['id']; - //$companyID = -1; if (is_array($invoice) && isset($invoice['company']) && is_array($invoice['company']) && count($invoice['company']) > 0) $companyID = $invoice['company'][0]['id']; - + // paying so need the customerID from settings otherwise just viewing so dont need to expose data + // WH: I've added this for future ease: + if ( is_array( $invoice ) && isset( $invoice['contact'] ) && is_array( $invoice['contact'] ) && count( $invoice['contact'] ) > 0 ) { + $contactID = $invoice['contact'][0]['id']; } - $ret['success'] = true; - $ret['data'] = array( - 'ID' => $invoice['id'], - 'cID' => $contactID - ); + // $companyID = -1; if (is_array($invoice) && isset($invoice['company']) && is_array($invoice['company']) && count($invoice['company']) > 0) $companyID = $invoice['company'][0]['id']; + + } + $ret['success'] = true; + $ret['data'] = array( + 'ID' => $invoice['id'], + 'cID' => $contactID, + ); - } + } - break; - case ZBS_TYPE_QUOTE: + break; + case ZBS_TYPE_QUOTE: + // retrieve, if any + $quote = $zbs->DAL->quotes->getQuote( + -1, + array( + 'hash' => $hash, + 'withAssigned' => true, + ) + ); - // retrieve, if any - $quote = $zbs->DAL->quotes->getQuote(-1,array('hash'=>$hash,'withAssigned'=>true)); + // got quote? + if ( is_array( $quote ) && isset( $quote['id'] ) ) { - // got quote? - if (is_array($quote) && isset($quote['id'])){ + $ret['success'] = true; + $ret['data'] = array( + 'ID' => $quote['id'], + 'cID' => -1, // not req for quotes? + ); - $ret['success'] = true; - $ret['data'] = array( - 'ID' => $quote['id'], - 'cID' => -1 // not req for quotes? - ); + } - } - - break; + break; - } // / switch + } // / switch - } // / if hash + objtypeid + } // / if hash + objtypeid - return $ret; - - } + return $ret; +} // ======== / Security Logs (used for Quote + Trans hashlink access) ============= // =============================================================================== - - // =============================================================================== // ======================= Tax Table Helpers ==================================== @@ -6131,7 +6253,7 @@ function zeroBSCRM_taxRates_getTaxValue( $subtotal = 0.0, $taxRateIDCSV = '' ) { $tax = 0.0; // retrieve tax rate(s) - if ( !empty( $taxRateIDCSV ) ) { + if ( ! empty( $taxRateIDCSV ) ) { $taxRateTable = zeroBSCRM_taxRates_getTaxTableArr( true ); @@ -6140,26 +6262,25 @@ function zeroBSCRM_taxRates_getTaxValue( $subtotal = 0.0, $taxRateIDCSV = '' ) { if ( strpos( $taxRateIDCSV, ',' ) ) { $taxRateIDs = explode( ',', $taxRateIDCSV ); - if ( !is_array( $taxRateIDs ) ) { + if ( ! is_array( $taxRateIDs ) ) { $taxRatesToApply = array(); } else { $taxRatesToApply = $taxRateIDs; } - } else { - $taxRatesToApply[] = (int)$taxRateIDCSV; + $taxRatesToApply[] = (int) $taxRateIDCSV; } if ( is_array( $taxRatesToApply ) ) { foreach ( $taxRatesToApply as $taxRateID ) { - $rateID = (int)$taxRateID; - if ( isset( $taxRateTable[$rateID] ) ) { + $rateID = (int) $taxRateID; + if ( isset( $taxRateTable[ $rateID ] ) ) { // get rate $rate = 0.0; - if ( isset( $taxRateTable[$rateID]['rate'] ) ) { - $rate = (float)$taxRateTable[$rateID]['rate']; + if ( isset( $taxRateTable[ $rateID ]['rate'] ) ) { + $rate = (float) $taxRateTable[ $rateID ]['rate']; } // calc + add @@ -6175,100 +6296,95 @@ function zeroBSCRM_taxRates_getTaxValue( $subtotal = 0.0, $taxRateIDCSV = '' ) { } return 0.0; - } - // gets single tax rate by id - function zeroBSCRM_taxRates_getTaxRate($taxRateID=''){ - - // retrieve tax rate(s) - if (!empty($taxRateID)){ +// gets single tax rate by id +function zeroBSCRM_taxRates_getTaxRate( $taxRateID = '' ) { - $taxRateID = (int)$taxRateID; + // retrieve tax rate(s) + if ( ! empty( $taxRateID ) ) { - global $ZBSCRM_t,$wpdb; + $taxRateID = (int) $taxRateID; - // for v3.0, brutal direct sql - $query = 'SELECT * FROM '.$ZBSCRM_t['tax'].' WHERE ID = %d ORDER BY ID ASC'; - try { + global $ZBSCRM_t, $wpdb; - #} Prep & run query - $queryObj = $wpdb->prepare($query,array($taxRateID)); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + // for v3.0, brutal direct sql + $query = 'SELECT * FROM ' . $ZBSCRM_t['tax'] . ' WHERE ID = %d ORDER BY ID ASC'; + try { - } catch (Exception $e){ + #} Prep & run query + $queryObj = $wpdb->prepare( $query, array( $taxRateID ) ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - - } + } catch ( Exception $e ) { - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && isset($potentialRes->ID)) { - - return zeroBSCRM_taxRates_tidy_taxRate($potentialRes); + } - } + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - } + return zeroBSCRM_taxRates_tidy_taxRate( $potentialRes ); - return array(); + } + } - } + return array(); +} - // retrieve tax table as array - function zeroBSCRM_taxRates_getTaxTableArr($indexByID=false){ +// retrieve tax table as array +function zeroBSCRM_taxRates_getTaxTableArr( $indexByID = false ) { - /* // demo/dummy data - return array( + /* + // demo/dummy data + return array( - //these will be populated based on the array - 1 => array( - 'id' => 1, - 'tax' => 20, - 'name' => 'VAT' - ), + //these will be populated based on the array + 1 => array( + 'id' => 1, + 'tax' => 20, + 'name' => 'VAT' + ), - 2 => array( - 'id' => 2, - 'tax' => 19, - 'name' => 'GST' - ) + 2 => array( + 'id' => 2, + 'tax' => 19, + 'name' => 'GST' + ) - ); */ + ); */ - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; - // for v3.0, brutal direct sql - $query = 'SELECT * FROM '.$ZBSCRM_t['tax'].' ORDER BY ID ASC'; - $potentialTaxRates = $wpdb->get_results($query, OBJECT); + // for v3.0, brutal direct sql + $query = 'SELECT * FROM ' . $ZBSCRM_t['tax'] . ' ORDER BY ID ASC'; + $potentialTaxRates = $wpdb->get_results( $query, OBJECT ); - #} Interpret results (Result Set - multi-row) - if (isset($potentialTaxRates) && is_array($potentialTaxRates) && count($potentialTaxRates) > 0) { + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialTaxRates ) && is_array( $potentialTaxRates ) && count( $potentialTaxRates ) > 0 ) { - $res = array(); + $res = array(); - #} Has results, tidy + return - foreach ($potentialTaxRates as $resDataLine) { - - if ($indexByID){ - - $lineID = (int)$resDataLine->ID; - $res[$lineID] = zeroBSCRM_taxRates_tidy_taxRate($resDataLine); + #} Has results, tidy + return + foreach ( $potentialTaxRates as $resDataLine ) { - } else { - - $res[] = zeroBSCRM_taxRates_tidy_taxRate($resDataLine); + if ( $indexByID ) { - } + $lineID = (int) $resDataLine->ID; + $res[ $lineID ] = zeroBSCRM_taxRates_tidy_taxRate( $resDataLine ); - } + } else { - return $res; - } + $res[] = zeroBSCRM_taxRates_tidy_taxRate( $resDataLine ); - return array(); + } + } + return $res; } + return array(); +} + /** * Generate a lookup key for tax rate duplicate detection * @@ -6280,38 +6396,54 @@ function jpcrm_tax_rates_generate_lookup_key( $name, $rate ) { return strtolower( trim( $name ) ) . '_' . number_format( (float) $rate, 4, '.', '' ); } - /** - * adds or updates a taxrate object - * - * @param array $args Associative array of arguments - * id (not req.), owner (not req.) data -> key/val - * - * @return int line ID - */ - function zeroBSCRM_taxRates_addUpdateTaxRate($args=array()){ + /** + * adds or updates a taxrate object + * + * @param array $args Associative array of arguments + * id (not req.), owner (not req.) data -> key/val + * + * @return int line ID + */ +function zeroBSCRM_taxRates_addUpdateTaxRate( $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( - 'name' => '', - 'rate' => 0.0, - 'created' => -1 // override date? :( - - ) + 'name' => '', + 'rate' => 0.0, + 'created' => -1, // override date? :( - ); 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; @@ -6360,330 +6492,338 @@ function zeroBSCRM_taxRates_addUpdateTaxRate($args=array()){ } } - #} ========= / 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 - 'zbsc_tax_name' => $data['name'], - 'zbsc_rate' => $data['rate'], - 'zbsc_lastupdated' => time() - ); - - $dataTypes = array( // field data types - '%d', + #} ========= / CHECK FIELDS =========== - '%s', - '%s', - '%d' - ); + $dataArr = array( - if (isset($data['created']) && !empty($data['created']) && $data['created'] !== -1){ - $dataArr['zbsc_created'] = $data['created']; $dataTypes[] = '%d'; - } + // 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 + 'zbsc_tax_name' => $data['name'], + 'zbsc_rate' => $data['rate'], + 'zbsc_lastupdated' => time(), + ); - 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['tax'], - $dataArr, - array( // where - 'ID' => $id - ), - $dataTypes, - array( // where data types - '%d' - )) !== false){ + $dataTypes = array( // field data types + '%d', - // Successfully updated - clear cache and return id - wp_cache_delete( 'all_tax_rates', 'zbscrm_tax_rates' ); - return $id; + '%s', + '%s', + '%d', + ); - } else { + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbsc_created'] = $data['created']; + $dataTypes[] = '%d'; + } - // FAILED update - return false; + if ( isset( $id ) && ! empty( $id ) && $id > 0 ) { - } + #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - } else { + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['tax'], + $dataArr, + array( // where + 'ID' => $id, + ), + $dataTypes, + array( // where data types + '%d', + ) + ) !== false ) { - // set created if not set - if (!isset($dataArr['zbsc_created'])) { - $dataArr['zbsc_created'] = time(); $dataTypes[] = '%d'; - } + // Successfully updated - clear cache and return id + wp_cache_delete( 'all_tax_rates', 'zbscrm_tax_rates' ); + return $id; - // 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['tax'], - $dataArr, - $dataTypes ) > 0){ + } else { - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; + // FAILED update + return false; - // Clear cache after successful insert - wp_cache_delete( 'all_tax_rates', 'zbscrm_tax_rates' ); + } + } else { - return $newID; + // set created if not set + if ( ! isset( $dataArr['zbsc_created'] ) ) { + $dataArr['zbsc_created'] = time(); + $dataTypes[] = '%d'; + } - } else { + // add team etc + $dataArr['zbs_site'] = zeroBSCRM_site(); + $dataTypes[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $dataTypes[] = '%d'; - #} Failed to Insert - return false; + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['tax'], + $dataArr, + $dataTypes + ) > 0 ) { - } + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; - } + // Clear cache after successful insert + wp_cache_delete( 'all_tax_rates', 'zbscrm_tax_rates' ); - return false; + return $newID; - } + } else { - /** - * deletes a Taxrate object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - function zeroBSCRM_taxRates_deleteTaxRate($args=array()){ + #} Failed to Insert + return false; - global $ZBSCRM_t,$wpdb; + } + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + return false; +} - 'id' => -1 + /** + * deletes a Taxrate object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ +function zeroBSCRM_taxRates_deleteTaxRate( $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; - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) return zeroBSCRM_db2_deleteGeneric($id,'tax'); + #} ============ LOAD ARGS ============= + $defaultArgs = array( - return false; + '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 ============ - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - function zeroBSCRM_taxRates_tidy_taxRate($obj=false){ + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + return zeroBSCRM_db2_deleteGeneric( $id, 'tax' ); + } - $res = false; + return false; +} - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - $res['owner'] = $obj->zbs_owner; - - $res['name'] = $obj->zbsc_tax_name; - $res['rate'] = $obj->zbsc_rate; + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ +function zeroBSCRM_taxRates_tidy_taxRate( $obj = false ) { - // to maintain old obj more easily, here we refine created into datestamp - $res['created'] = zeroBSCRM_locale_utsToDatetime($obj->zbsc_created); - $res['createduts'] = $obj->zbsc_created; // this is the UTS (int14) + $res = false; - $res['lastupdated'] = $obj->zbsc_lastupdated; + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + $res['owner'] = $obj->zbs_owner; - } + $res['name'] = $obj->zbsc_tax_name; + $res['rate'] = $obj->zbsc_rate; - return $res; + // to maintain old obj more easily, here we refine created into datestamp + $res['created'] = zeroBSCRM_locale_utsToDatetime( $obj->zbsc_created ); + $res['createduts'] = $obj->zbsc_created; // this is the UTS (int14) + $res['lastupdated'] = $obj->zbsc_lastupdated; - } + } + return $res; +} // ======================= / Tax Table Helpers =================================== // =============================================================================== - // =============================================================================== // ======================= File Upload Related Funcs ============================ // retrieve all files for a (customer)whatever - function zeroBSCRM_files_getFiles($fileType = '',$objID=-1){ +function zeroBSCRM_files_getFiles( $fileType = '', $objID = -1 ) { - global $zbs; + global $zbs; - $filesArrayKey = zeroBSCRM_files_key($fileType); - - if (!empty($filesArrayKey) && $objID > 0){ + $filesArrayKey = zeroBSCRM_files_key( $fileType ); - // DAL2+ - // bit gross hard-typed, could be genericified as all is using is >DAL()->getMeta - switch ($fileType){ + if ( ! empty( $filesArrayKey ) && $objID > 0 ) { - case 'customer': - case 'contact': - return $zbs->DAL->contacts->getContactMeta($objID,'files'); - break; + // DAL2+ + // bit gross hard-typed, could be genericified as all is using is >DAL()->getMeta + switch ( $fileType ) { - case 'quotes': - case 'quote': - return $zbs->DAL->quotes->getQuoteMeta($objID,'files'); - break; + case 'customer': + case 'contact': + return $zbs->DAL->contacts->getContactMeta( $objID, 'files' ); + break; - case 'invoices': - case 'invoice': - return $zbs->DAL->invoices->getInvoiceMeta($objID,'files'); - break; + case 'quotes': + case 'quote': + return $zbs->DAL->quotes->getQuoteMeta( $objID, 'files' ); + break; - case 'companies': - case 'company': - return $zbs->DAL->companies->getCompanyMeta($objID,'files'); - break; + case 'invoices': + case 'invoice': + return $zbs->DAL->invoices->getInvoiceMeta( $objID, 'files' ); + break; - // no default + case 'companies': + case 'company': + return $zbs->DAL->companies->getCompanyMeta( $objID, 'files' ); + break; - } + // no default } - - return array(); } - // updates files array for a (whatever) - function zeroBSCRM_files_updateFiles($fileType = '',$objID=-1,$filesArray=-1){ - - global $zbs; - - $filesArrayKey = zeroBSCRM_files_key($fileType); - - if (!empty($filesArrayKey) && $objID > 0){ - - - // DAL2+ - // bit gross hard-typed, could be genericified as all is using is >DAL()->getMeta - switch ($fileType){ - - case 'customer': - case 'contact': - $zbs->DAL->updateMeta(ZBS_TYPE_CONTACT,$objID,'files',$filesArray); - break; - - case 'quotes': - case 'quote': - $zbs->DAL->updateMeta(ZBS_TYPE_QUOTE,$objID,'files',$filesArray); - break; - - case 'invoices': - case 'invoice': - $zbs->DAL->updateMeta(ZBS_TYPE_INVOICE,$objID,'files',$filesArray); - break; - - case 'companies': - case 'company': - $zbs->DAL->updateMeta(ZBS_TYPE_COMPANY,$objID,'files',$filesArray); - break; - - // no default - - } - - - return $filesArray; + return array(); +} - } +// updates files array for a (whatever) +function zeroBSCRM_files_updateFiles( $fileType = '', $objID = -1, $filesArray = -1 ) { - return false; - } + global $zbs; - // gets meta key for file type arr - function zeroBSCRM_files_key($fileType=''){ + $filesArrayKey = zeroBSCRM_files_key( $fileType ); + if ( ! empty( $filesArrayKey ) && $objID > 0 ) { - switch ($fileType){ + // DAL2+ + // bit gross hard-typed, could be genericified as all is using is >DAL()->getMeta + switch ( $fileType ) { case 'customer': case 'contact': - - return 'zbs_customer_files'; - + $zbs->DAL->updateMeta( ZBS_TYPE_CONTACT, $objID, 'files', $filesArray ); break; + case 'quotes': case 'quote': - - return 'zbs_customer_quotes'; - + $zbs->DAL->updateMeta( ZBS_TYPE_QUOTE, $objID, 'files', $filesArray ); break; + case 'invoices': case 'invoice': - - return 'zbs_customer_invoices'; - + $zbs->DAL->updateMeta( ZBS_TYPE_INVOICE, $objID, 'files', $filesArray ); break; case 'companies': case 'company': - - return 'zbs_company_files'; - + $zbs->DAL->updateMeta( ZBS_TYPE_COMPANY, $objID, 'files', $filesArray ); break; + // no default + } - return ''; + return $filesArray; + } -// ======================= / File Upload Related Funcs =========================== -// =============================================================================== + return false; +} + +// gets meta key for file type arr +function zeroBSCRM_files_key( $fileType = '' ) { + + switch ( $fileType ) { + + case 'customer': + case 'contact': + return 'zbs_customer_files'; + + break; + case 'quotes': + case 'quote': + return 'zbs_customer_quotes'; + + break; + case 'invoices': + case 'invoice': + return 'zbs_customer_invoices'; + break; + case 'companies': + case 'company': + return 'zbs_company_files'; + break; + + } + + return ''; +} + +// ======================= / File Upload Related Funcs =========================== // =============================================================================== -// =========== TEMPHASH (remains same for DAL2->3) ============================= +// =============================================================================== +// =========== TEMPHASH (remains same for DAL2->3) ============================= - /** +/** * checks validity of a temporary hash object * * @return int success; */ - function zeroBSCRM_checkValidTempHash($objid=-1,$type='',$hash=''){ +function zeroBSCRM_checkValidTempHash( $objid = -1, $type = '', $hash = '' ) { - // get a valid hash - $hash = zeroBSCRM_getTempHash(-1,$type,$hash,1); - - // check id - if (isset($hash) && is_array($hash) && isset($hash['objid'])) if ($objid == $hash['objid']) return true; + // get a valid hash + $hash = zeroBSCRM_getTempHash( -1, $type, $hash, 1 ); - return false; + // check id + if ( isset( $hash ) && is_array( $hash ) && isset( $hash['objid'] ) ) { + if ( $objid == $hash['objid'] ) { + return true; + } + } - } + return false; +} - /** +/** * retrieves a temporary hash object * * @return int success; */ - function zeroBSCRM_getTempHash($id=-1,$type='',$hash='',$status=-99){ +function zeroBSCRM_getTempHash( $id = -1, $type = '', $hash = '', $status = -99 ) { - $id = (int)$id; - if (!empty($id) && $id > 0){ + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; $additionalWHERE = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $queryVars = array(); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -6691,364 +6831,376 @@ function zeroBSCRM_getTempHash($id=-1,$type='',$hash='',$status=-99){ $queryVars[] = $id; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $whereStr = 'ID = %d'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if (!empty($type)){ + if ( ! empty( $type ) ) { - $queryVars[] = $type; + $queryVars[] = $type; $additionalWHERE = 'AND zbstemphash_objtype = %s '; } // else will be from ANY type + if ( $status != -99 ) { - if ($status != -99){ - - $queryVars[] = $status; + $queryVars[] = $status; $additionalWHERE = 'AND zbstemphash_status = %d '; } /* -- prep started, see: #OWNERSHIP */ - $sql = "SELECT * FROM ".$ZBSCRM_t['temphash']." WHERE ".$whereStr." ".$additionalWHERE."ORDER BY ID ASC LIMIT 0,1"; + $sql = 'SELECT * FROM ' . $ZBSCRM_t['temphash'] . ' WHERE ' . $whereStr . ' ' . $additionalWHERE . 'ORDER BY ID ASC LIMIT 0,1'; - $potentialReponse = $wpdb->get_row( $wpdb->prepare($sql,$queryVars), OBJECT ); + $potentialReponse = $wpdb->get_row( $wpdb->prepare( $sql, $queryVars ), OBJECT ); - if (isset($potentialReponse) && isset($potentialReponse->ID)){ + if ( isset( $potentialReponse ) && isset( $potentialReponse->ID ) ) { - #} Retrieved :) fill + return - - // tidy - $res = zeroBS_tidy_temphash($potentialReponse); + #} Retrieved :) fill + return - return $res; - } + // tidy + $res = zeroBS_tidy_temphash( $potentialReponse ); + return $res; } - - return false; - - } - /** + return false; +} + +/** * adds or updates a temporary hash object * * @return int success; */ - function zeroBSCRM_addUpdateTempHash($id=-1,$objstatus=-1,$objtype='',$objid=-1,$objhash='',$returnHashArr=false){ +function zeroBSCRM_addUpdateTempHash( $id = -1, $objstatus = -1, $objtype = '', $objid = -1, $objhash = '', $returnHashArr = false ) { // globals - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; // got id? - $id = (int)$id; - if (!empty($id) && $id > 0){ - - // check exists? - - // for now just brutal update. - if ($wpdb->update( - $ZBSCRM_t['temphash'], - array( - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => zeroBSCRM_currentUserID(), - - 'zbstemphash_status' => (int)$objstatus, - 'zbstemphash_objtype' => $objtype, - 'zbstemphash_objid' => (int)$objid, - 'zbstemphash_objhash' => $objhash, - - //'zbsmaillink_created' => time(), - 'zbstemphash_lastupdated' => time() - ), - array( // where - 'ID' => $id - ), - array( - '%d', - '%s', - '%d', - '%s', - '%d' - ), - array( - '%d' - ) - ) !== false){ + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + + // check exists? - // if "return hash" - if ($returnHashArr) return array('id'=>$id,'hash'=>$objhash); + // for now just brutal update. + if ( $wpdb->update( + $ZBSCRM_t['temphash'], + array( + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => zeroBSCRM_currentUserID(), - // return id - return $id; + 'zbstemphash_status' => (int) $objstatus, + 'zbstemphash_objtype' => $objtype, + 'zbstemphash_objid' => (int) $objid, + 'zbstemphash_objhash' => $objhash, - } + // 'zbsmaillink_created' => time(), + 'zbstemphash_lastupdated' => time(), + ), + array( // where + 'ID' => $id, + ), + array( + '%d', + '%s', + '%d', + '%s', + '%d', + ), + array( + '%d', + ) + ) !== false ) { + // if "return hash" + if ( $returnHashArr ) { + return array( + 'id' => $id, + 'hash' => $objhash, + ); + } + // return id + return $id; + } } else { - + // insert // create hash if not created :) - if (empty($objhash)) $objhash = zeroBSCRM_GenerateTempHash(); + if ( empty( $objhash ) ) { + $objhash = zeroBSCRM_GenerateTempHash(); + } // go - if ($wpdb->insert( - $ZBSCRM_t['temphash'], - array( - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => zeroBSCRM_currentUserID(), - - 'zbstemphash_status' => (int)$objstatus, - 'zbstemphash_objtype' => $objtype, - 'zbstemphash_objid' => (int)$objid, - 'zbstemphash_objhash' => $objhash, - - 'zbstemphash_created' => time(), - 'zbstemphash_lastupdated' => time() - ), - array( - //'%d', // site - //'%d', // team - //'%d', // owner - - '%d', - '%s', - '%d', - '%s', - '%d', - '%d' - ) - ) > 0){ + if ( $wpdb->insert( + $ZBSCRM_t['temphash'], + array( + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => zeroBSCRM_currentUserID(), + + 'zbstemphash_status' => (int) $objstatus, + 'zbstemphash_objtype' => $objtype, + 'zbstemphash_objid' => (int) $objid, + 'zbstemphash_objhash' => $objhash, + + 'zbstemphash_created' => time(), + 'zbstemphash_lastupdated' => time(), + ), + array( + // '%d', // site + // '%d', // team + // '%d', // owner + + '%d', + '%s', + '%d', + '%s', + '%d', + '%d', + ) + ) > 0 ) { // inserted, let's move on $newID = $wpdb->insert_id; // if "return hash" - if ($returnHashArr) return array('id'=>$id,'hash'=>$objhash); - - return $newID; + if ( $returnHashArr ) { + return array( + 'id' => $id, + 'hash' => $objhash, + ); } + return $newID; + } } return false; - } - /** +/** * deletes a temporary hash object * * @param array $args Associative array of arguments - * id + * id * * @return int success; */ -function zeroBSCRM_deleteTempHash($args=array()){ +function zeroBSCRM_deleteTempHash( $args = array() ) { // Load Args $defaultArgs = array( - 'id' => -1 + 'id' => -1, - ); foreach ($defaultArgs as $argK => $argV){ $$argK = $argV; if (is_array($args) && isset($args[$argK])) $$argK = $args[$argK]; } + ); + foreach ( $defaultArgs as $argK => $argV ) { + $$argK = $argV; + if ( is_array( $args ) && isset( $args[ $argK ] ) ) { + $$argK = $args[ $argK ]; + } + } // globals - global $ZBSCRM_t,$wpdb; - - $id = (int)$id; - if (!empty($id) && $id > 0) return zeroBSCRM_db2_deleteGeneric($id,'temphash'); + global $ZBSCRM_t, $wpdb; - return false; + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + return zeroBSCRM_db2_deleteGeneric( $id, 'temphash' ); + } + return false; } -function zeroBS_tidy_temphash($obj=false){ +function zeroBS_tidy_temphash( $obj = false ) { - $res = false; + $res = false; - if (isset($obj->ID)){ - $res = array(); - $res['id'] = $obj->ID; - $res['created'] = $obj->zbstemphash_created; + if ( isset( $obj->ID ) ) { + $res = array(); + $res['id'] = $obj->ID; + $res['created'] = $obj->zbstemphash_created; $res['lastupdated'] = $obj->zbstemphash_lastupdated; - $res['status'] = $obj->zbstemphash_status; + $res['status'] = $obj->zbstemphash_status; $res['objtype'] = $obj->zbstemphash_objtype; - $res['objid'] = $obj->zbstemphash_objid; + $res['objid'] = $obj->zbstemphash_objid; $res['objhash'] = $obj->zbstemphash_objhash; - } + } return $res; - } // generates generic HASH (used for links etc.) -function zeroBSCRM_GenerateTempHash($str=-1,$length=20){ +function zeroBSCRM_GenerateTempHash( $str = -1, $length = 20 ) { #} Brutal hash generator, for now - if (!empty($str)){ + if ( ! empty( $str ) ) { #} Semi-nonsense, not "secure" - //$newMD5 = md5($postID.time().'fj30948hjfaosindf'); + // $newMD5 = md5($postID.time().'fj30948hjfaosindf'); - $newMD5 = wp_generate_password(64, false); + $newMD5 = wp_generate_password( 64, false ); - return substr($newMD5,0,$length-1); + return substr( $newMD5, 0, $length - 1 ); } return ''; - } // =========== / TEMPHASH ====================================================== // =============================================================================== - - - - -/* ====================================================== - General/WP helpers - ====================================================== */ +/* +====================================================== + General/WP helpers +====================================================== */ // in effect this is: get owner (WP USER)'s email // currently only used on Automations extension // use jpcrm_get_obj_owner_wordpress_email() in future... - function zeroBS_getAssigneeEmail( $cID=-1 ) { - return jpcrm_get_obj_owner_wordpress_email( $cID, ZBS_TYPE_CONTACT ); - } - +function zeroBS_getAssigneeEmail( $cID = -1 ) { + return jpcrm_get_obj_owner_wordpress_email( $cID, ZBS_TYPE_CONTACT ); +} // returns an obj owner's email as set against their WordPress account - function jpcrm_get_obj_owner_wordpress_email( $objID, $objTypeID ) { - - global $zbs; - if ( $objID > 0 && $zbs->DAL->isValidObjTypeID( $objTypeID ) ) { +function jpcrm_get_obj_owner_wordpress_email( $objID, $objTypeID ) { - $ownerID = zeroBS_getOwner( $objID, false, $objTypeID ); + global $zbs; + if ( $objID > 0 && $zbs->DAL->isValidObjTypeID( $objTypeID ) ) { - if ( $ownerID > 0 ) { - return get_the_author_meta( 'user_email', $ownerID ); - } + $ownerID = zeroBS_getOwner( $objID, false, $objTypeID ); + if ( $ownerID > 0 ) { + return get_the_author_meta( 'user_email', $ownerID ); } - - return false; - } + return false; +} // in effect this is: get owner (WP USER)'s mobile - // use zeroBS_getObjOwnerWPMobile in future... (renamed, bad naming) - function zeroBS_getAssigneeMobile($wpUID=-1){ - return zeroBS_getObjOwnerWPMobile($wpUID); - } + // use zeroBS_getObjOwnerWPMobile in future... (renamed, bad naming) +function zeroBS_getAssigneeMobile( $wpUID = -1 ) { + return zeroBS_getObjOwnerWPMobile( $wpUID ); +} // returns owner of obj's mobile (from WP USER) - function zeroBS_getObjOwnerWPMobile($objID =-1,$objType='zerobs_customer'){ +function zeroBS_getObjOwnerWPMobile( $objID = -1, $objType = 'zerobs_customer' ) { - if ($objID > 0){ + if ( $objID > 0 ) { - $ownerID = zeroBS_getOwner($objID,false,$objType); + $ownerID = zeroBS_getOwner( $objID, false, $objType ); - if ($ownerID > 0) return zeroBS_getWPUsersMobile($ownerID); - + if ( $ownerID > 0 ) { + return zeroBS_getWPUsersMobile( $ownerID ); } - - return false; - } - // returns an obj owner's mobile number as per their wp account - function zeroBS_getWPUsersMobile($uID =-1){ - if ($uID !== -1){ - if (!empty($uID)){ - $mobile_number = get_user_meta( 'mobile_number', $uID ); - $mobile_number = apply_filters( 'zbs_filter_mobile', $mobile_number); - return $mobile_number; - } - return false; + return false; +} + + // returns an obj owner's mobile number as per their wp account +function zeroBS_getWPUsersMobile( $uID = -1 ) { + if ( $uID !== -1 ) { + if ( ! empty( $uID ) ) { + $mobile_number = get_user_meta( 'mobile_number', $uID ); + $mobile_number = apply_filters( 'zbs_filter_mobile', $mobile_number ); + return $mobile_number; } + return false; } +} /* * Gets formatted display name for user (tries to retrieve fname lname) */ - function jpcrm_wp_user_name( $wordpress_user_id=-1 ){ +function jpcrm_wp_user_name( $wordpress_user_id = -1 ) { - $user_info = get_userdata( $wordpress_user_id ); - if ( !$user_info ) return false; - - // start with display name - $user_name = $user_info->display_name; - - // else try and use fname lname - if ( empty( $user_name ) ){ - $user_name = $user_info->user_firstname; - if ( !empty( $user_info->user_lastname ) ){ + $user_info = get_userdata( $wordpress_user_id ); + if ( ! $user_info ) { + return false; + } - if ( !empty( $user_name ) ){ - $user_name .= ' '; - } + // start with display name + $user_name = $user_info->display_name; - $user_name .= $user_info->user_lastname; + // else try and use fname lname + if ( empty( $user_name ) ) { + $user_name = $user_info->user_firstname; + if ( ! empty( $user_info->user_lastname ) ) { - } - } + if ( ! empty( $user_name ) ) { + $user_name .= ' '; + } - // else fall back to nice name - if ( empty( $user_name ) ){ - $user_name = $user_info->user_nicename; - } + $user_name .= $user_info->user_lastname; - // else email? - if ( empty( $user_name ) ){ - $user_name = $user_info->user_email; - } + } + } - return $user_name; + // else fall back to nice name + if ( empty( $user_name ) ) { + $user_name = $user_info->user_nicename; + } + // else email? + if ( empty( $user_name ) ) { + $user_name = $user_info->user_email; } - /// ======= Statuses wrappers - bit antiquated now... + return $user_name; +} - // outdated wrapper - function zeroBS_getTransactionsStatuses(){ return zeroBSCRM_getTransactionsStatuses(); } + // ======= Statuses wrappers - bit antiquated now... + // outdated wrapper +function zeroBS_getTransactionsStatuses() { + return zeroBSCRM_getTransactionsStatuses(); +} - function zeroBSCRM_getCustomerStatuses($asArray=false){ +function zeroBSCRM_getCustomerStatuses( $asArray = false ) { - global $zbs; + global $zbs; - $setting = $zbs->DAL->setting('customisedfields',false); + $setting = $zbs->DAL->setting( 'customisedfields', false ); - $zbsStatusStr = ''; + $zbsStatusStr = ''; - #} stored here: $settings['customisedfields'] - if (is_array($setting) && isset($setting['customers']['status']) && is_array($setting['customers']['status'])) $zbsStatusStr = $setting['customers']['status'][1]; - if (empty($zbsStatusStr)) { - #} Defaults: - global $zbsCustomerFields; if (is_array($zbsCustomerFields)) $zbsStatusStr = implode(',',$zbsCustomerFields['status'][3]); - } + #} stored here: $settings['customisedfields'] + if ( is_array( $setting ) && isset( $setting['customers']['status'] ) && is_array( $setting['customers']['status'] ) ) { + $zbsStatusStr = $setting['customers']['status'][1]; + } + if ( empty( $zbsStatusStr ) ) { + #} Defaults: + global $zbsCustomerFields; + if ( is_array( $zbsCustomerFields ) ) { + $zbsStatusStr = implode( ',', $zbsCustomerFields['status'][3] ); + } + } - if ($asArray){ + if ( $asArray ) { if ( str_contains( '#' . $zbsStatusStr, ',' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $arr = explode(',',$zbsStatusStr); - $ret = array(); - foreach ($arr as $x) { $z = trim($x); if (!empty($z)) $ret[] = $z; } - - return $ret; - - } + $arr = explode( ',', $zbsStatusStr ); + $ret = array(); + foreach ( $arr as $x ) { + $z = trim( $x ); + if ( ! empty( $z ) ) { + $ret[] = $z; + } + } - } + return $ret; - return $zbsStatusStr; } + } + + return $zbsStatusStr; +} /** * Retrieve valid transaction statuses @@ -7098,24 +7250,28 @@ function zeroBSCRM_getInvoicesStatuses() { ); } +function zeroBSCRM_getCompanyStatusesCSV() { - function zeroBSCRM_getCompanyStatusesCSV(){ - - global $zbs; - - $setting = $zbs->DAL->setting('customisedfields',false); + global $zbs; - $zbsStatusStr = ''; + $setting = $zbs->DAL->setting( 'customisedfields', false ); - #} stored here: $settings['customisedfields'] - if (is_array($setting) && isset($setting['companies']['status']) && is_array($setting['companies']['status'])) $zbsStatusStr = $setting['companies']['status'][1]; - if (empty($zbsStatusStr)) { - #} Defaults: - global $zbsCompanyFields; if (is_array($zbsCompanyFields)) $zbsStatusStr = implode(',',$zbsCompanyFields['status'][3]); - } + $zbsStatusStr = ''; - return $zbsStatusStr; + #} stored here: $settings['customisedfields'] + if ( is_array( $setting ) && isset( $setting['companies']['status'] ) && is_array( $setting['companies']['status'] ) ) { + $zbsStatusStr = $setting['companies']['status'][1]; + } + if ( empty( $zbsStatusStr ) ) { + #} Defaults: + global $zbsCompanyFields; + if ( is_array( $zbsCompanyFields ) ) { + $zbsStatusStr = implode( ',', $zbsCompanyFields['status'][3] ); } + } + + return $zbsStatusStr; +} /** * Retrieve an array of valid company statuses @@ -7130,132 +7286,136 @@ function zeroBSCRM_getCompanyStatuses() { } } - /// ======= / Statuses wrappers - bit antiquated now... + // ======= / Statuses wrappers - bit antiquated now... // DELETES ALL rows from any table, based on ID // no limits! be careful. - function zeroBSCRM_db2_deleteGeneric($id=-1,$tableKey=''){ - - // req - global $ZBSCRM_t,$wpdb; +function zeroBSCRM_db2_deleteGeneric( $id = -1, $tableKey = '' ) { - // lazy id check - $id = (int)$id; - if ( $id > 0 && !empty($tableKey) && array_key_exists( $tableKey, $ZBSCRM_t ) ){ + // req + global $ZBSCRM_t, $wpdb; - return $wpdb->delete( - $ZBSCRM_t[$tableKey], - array( // where - 'ID' => $id - ), - array( - '%d' - ) - ); + // lazy id check + $id = (int) $id; + if ( $id > 0 && ! empty( $tableKey ) && array_key_exists( $tableKey, $ZBSCRM_t ) ) { - } + return $wpdb->delete( + $ZBSCRM_t[ $tableKey ], + array( // where + 'ID' => $id, + ), + array( + '%d', + ) + ); - return false; } - // this has a js equivilent in global.js: zeroBSCRMJS_telURLFromNo - function zeroBSCRM_clickToCallPrefix(){ + return false; +} - $click2CallType = zeroBSCRM_getSetting('clicktocalltype'); + // this has a js equivilent in global.js: zeroBSCRMJS_telURLFromNo +function zeroBSCRM_clickToCallPrefix() { - if ($click2CallType == 1) return 'tel:'; - if ($click2CallType == 2) return 'callto:'; + $click2CallType = zeroBSCRM_getSetting( 'clicktocalltype' ); - } + if ( $click2CallType == 1 ) { + return 'tel:'; + } + if ( $click2CallType == 2 ) { + return 'callto:'; + } +} - function zeroBS_getCurrentUserUsername(){ +function zeroBS_getCurrentUserUsername() { - // https://codex.wordpress.org/Function_Reference/wp_get_current_user + // https://codex.wordpress.org/Function_Reference/wp_get_current_user - $current_user = wp_get_current_user(); - if ( !($current_user instanceof WP_User) ) return; - return $current_user->user_login; + $current_user = wp_get_current_user(); + if ( ! ( $current_user instanceof WP_User ) ) { + return; } + return $current_user->user_login; +} #} ZBS users page - returns list of WP user IDs, which have a ZBS role and includes name / email, etc - function zeroBSCRM_crm_users_list(){ - //from Permissions - /* - remove_role('zerobs_admin'); - remove_role('zerobs_customermgr'); - remove_role('zerobs_quotemgr'); - remove_role('zerobs_invoicemgr'); - remove_role('zerobs_transactionmgr'); - remove_role('zerobs_customer'); - remove_role('zerobs_mailmgr'); - - */ - //NOT zerbs_customer - this is people who have purchased (i.e. WooCommerce folk) - $role = array('zerobs_customermgr','zerobs_admin','administrator','zerobs_quotemgr', 'zerobs_invoicemgr', 'zerobs_transactionmgr', 'zerobs_mailmgr'); - $crm_users = get_users(array('role__in' => $role, 'orderby' => 'ID')); +function zeroBSCRM_crm_users_list() { + // from Permissions + /* + remove_role('zerobs_admin'); + remove_role('zerobs_customermgr'); + remove_role('zerobs_quotemgr'); + remove_role('zerobs_invoicemgr'); + remove_role('zerobs_transactionmgr'); + remove_role('zerobs_customer'); + remove_role('zerobs_mailmgr'); - //this will return what WP holds (and can interpret on the outside.) - return $crm_users; + */ + // NOT zerbs_customer - this is people who have purchased (i.e. WooCommerce folk) + $role = array( 'zerobs_customermgr', 'zerobs_admin', 'administrator', 'zerobs_quotemgr', 'zerobs_invoicemgr', 'zerobs_transactionmgr', 'zerobs_mailmgr' ); + $crm_users = get_users( + array( + 'role__in' => $role, + 'orderby' => 'ID', + ) + ); - } + // this will return what WP holds (and can interpret on the outside.) + return $crm_users; +} - // returns a system setting for ignore ownership // ... ownership ignored, unless the setting is on + not admin - function zeroBSCRM_DAL2_ignoreOwnership($objType=1){ - - global $zbs; +function zeroBSCRM_DAL2_ignoreOwnership( $objType = 1 ) { - // FOR NOW EVERYONE CAN SEE EVERYTHING - // Later add - strict ownership? isn't this a platform UPSELL? - // if ($zbs->settings->get('perusercustomers') && !current_user_can('administrator')) return false; - - return true; + global $zbs; - } + // FOR NOW EVERYONE CAN SEE EVERYTHING + // Later add - strict ownership? isn't this a platform UPSELL? + // if ($zbs->settings->get('perusercustomers') && !current_user_can('administrator')) return false; - function zeroBSCRM_DEPRECATEDMSG($msg=''){ + return true; +} - echo '
'.$msg.'
'; - error_log(strip_tags($msg)); +function zeroBSCRM_DEPRECATEDMSG( $msg = '' ) { - } + echo '
' . $msg . '
'; + error_log( strip_tags( $msg ) ); +} /** * This takes a passed object type (old or new) and returns the new type. - * + * * @param string|int - an object type in old or new format, e.g.: * old: 'zerobs_customer' * new: 1, ZBS_TYPE_CONTACT - * + * * @return int|bool false - the object type ID if it exists, false if not */ - function jpcrm_upconvert_obj_type( $obj_type=-1 ) { - global $zbs; +function jpcrm_upconvert_obj_type( $obj_type = -1 ) { + global $zbs; - if ( $zbs->DAL->isValidObjTypeID( $obj_type ) ) { - // already a valid new obj? - return (int)$obj_type; - } - else { - // upconvert old type into new - return $zbs->DAL->objTypeID( $obj_type ); - } + if ( $zbs->DAL->isValidObjTypeID( $obj_type ) ) { + // already a valid new obj? + return (int) $obj_type; + } else { + // upconvert old type into new + return $zbs->DAL->objTypeID( $obj_type ); } +} /** * Backward compat - `zbsLink` got renamed to `jpcrm_esc_link` in 5.5 **/ - function zbsLink( $key = '', $id = -1, $type = 'zerobs_customer', $prefixOnly = false, $taxonomy = false ){ +function zbsLink( $key = '', $id = -1, $type = 'zerobs_customer', $prefixOnly = false, $taxonomy = false ) { - return jpcrm_esc_link( $key, $id, $type, $prefixOnly, $taxonomy ); - - } + return jpcrm_esc_link( $key, $id, $type, $prefixOnly, $taxonomy ); +} /** * Core Link building function * Produces escaped raw URLs for links within wp-admin based CRM areas - * + * Examples: echo 'New Contact'; echo 'Edit Contact'; @@ -7264,240 +7424,249 @@ function zbsLink( $key = '', $id = -1, $type = 'zerobs_customer', $prefixOnly = * - accepts new (contact,ZBS_TYPE_CONTACT) or old (zerobs_customer) references (but use NEW going forward) * - previously called `zbsLink` **/ - function jpcrm_esc_link( $key = '', $id = -1, $type = 'zerobs_customer', $prefixOnly = false, $taxonomy = false ){ - - global $zbs; +function jpcrm_esc_link( $key = '', $id = -1, $type = 'zerobs_customer', $prefixOnly = false, $taxonomy = false ) { - // infer objTypeID (turns contact|zerobs_contact -> ZBS_TYPE_CONTACT) - $objTypeID = jpcrm_upconvert_obj_type( $type ); - - // switch through potentials - switch ($key){ + global $zbs; - case 'list': + // infer objTypeID (turns contact|zerobs_contact -> ZBS_TYPE_CONTACT) + $objTypeID = jpcrm_upconvert_obj_type( $type ); - $url = admin_url('admin.php?page='.$zbs->slugs['dash']); + // switch through potentials + switch ( $key ) { - // switch based on type. - switch ($objTypeID){ + case 'list': + $url = admin_url( 'admin.php?page=' . $zbs->slugs['dash'] ); - case ZBS_TYPE_CONTACT: $url = admin_url( 'admin.php?page='.$zbs->slugs['managecontacts'] ); break; - case ZBS_TYPE_COMPANY: $url = admin_url( 'admin.php?page='.$zbs->slugs['managecompanies'] ); break; - case ZBS_TYPE_QUOTE: $url = admin_url( 'admin.php?page='.$zbs->slugs['managequotes'] ); break; - case ZBS_TYPE_INVOICE: $url = admin_url( 'admin.php?page='.$zbs->slugs['manageinvoices'] ); break; - case ZBS_TYPE_TRANSACTION: $url = admin_url( 'admin.php?page='.$zbs->slugs['managetransactions'] ); break; - case ZBS_TYPE_FORM: $url = admin_url( 'admin.php?page='.$zbs->slugs['manageformscrm'] ); break; - case ZBS_TYPE_TASK: $url = admin_url( 'admin.php?page='.$zbs->slugs['manage-tasks'] ); break; - case ZBS_TYPE_SEGMENT: $url = admin_url( 'admin.php?page='.$zbs->slugs['segments'] ); break; - case ZBS_TYPE_QUOTETEMPLATE: $url = admin_url( 'admin.php?page='.$zbs->slugs['quote-templates'] ); break; + // switch based on type. + switch ( $objTypeID ) { - } + case ZBS_TYPE_CONTACT: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['managecontacts'] ); + break; + case ZBS_TYPE_COMPANY: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['managecompanies'] ); + break; + case ZBS_TYPE_QUOTE: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['managequotes'] ); + break; + case ZBS_TYPE_INVOICE: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['manageinvoices'] ); + break; + case ZBS_TYPE_TRANSACTION: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['managetransactions'] ); + break; + case ZBS_TYPE_FORM: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['manageformscrm'] ); + break; + case ZBS_TYPE_TASK: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['manage-tasks'] ); + break; + case ZBS_TYPE_SEGMENT: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['segments'] ); + break; + case ZBS_TYPE_QUOTETEMPLATE: + $url = admin_url( 'admin.php?page=' . $zbs->slugs['quote-templates'] ); + break; - // rather than return admin.php?page=list, send to dash if not these ^ - return esc_url_raw( $url ); + } - break; + // rather than return admin.php?page=list, send to dash if not these ^ + return esc_url_raw( $url ); - case 'view': + break; - // view page (theoretically returns for all obj types, even tho contact + company only ones using view pages atm) - if ($objTypeID > 0){ + case 'view': + // view page (theoretically returns for all obj types, even tho contact + company only ones using view pages atm) + if ( $objTypeID > 0 ) { - if ($id > 0) { + if ( $id > 0 ) { - // view with actual ID - return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=view&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' . $id ) ); + // view with actual ID + return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=view&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' . $id ) ); - } else if ($prefixOnly){ + } elseif ( $prefixOnly ) { - // prefix only - return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=view&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' ) ); + // prefix only + return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=view&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' ) ); - } + } + } // / got objType + break; - } // / got objType - break; + case 'edit': + // edit page (returns for all obj types) + if ( $objTypeID > 0 ) { - case 'edit': + if ( $id > 0 ) { - // edit page (returns for all obj types) - if ($objTypeID > 0){ + // view with actual ID + return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=edit&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' . $id ) ); - if ($id > 0) { + } elseif ( $prefixOnly ) { - // view with actual ID - return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=edit&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' . $id ) ); + // prefix only + return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=edit&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' ) ); - } else if ( $prefixOnly ){ + } + } // / got objType + break; + case 'create': + // create page (returns for all obj types) + if ( $objTypeID > 0 ) { - // prefix only - return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=edit&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' ) ) ; + return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=edit&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) ) ); - } + } // / got objType - } // / got objType - break; - case 'create': + // mail campaigns specific catch + if ( $type == 'mailcampaign' || $type == 'mailsequence' ) { + global $zeroBSCRM_MailCampaignsslugs; + if ( isset( $zeroBSCRM_MailCampaignsslugs ) ) { + return esc_url_raw( admin_url( 'admin.php?page=' . $zeroBSCRM_MailCampaignsslugs['editcamp'] ) ); + } + } - // create page (returns for all obj types) - if ( $objTypeID > 0 ){ + break; - return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=edit&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) ) ); + case 'delete': + // delete page + if ( $objTypeID > 0 ) { - } // / got objType + if ( $id > 0 ) { - // mail campaigns specific catch - if ($type == 'mailcampaign' || $type == 'mailsequence'){ - global $zeroBSCRM_MailCampaignsslugs; if (isset($zeroBSCRM_MailCampaignsslugs)){ - return esc_url_raw( admin_url( 'admin.php?page=' . $zeroBSCRM_MailCampaignsslugs['editcamp'] ) ); - } - } + // view with actual ID + return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=delete&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' . $id ) ); - break; + } elseif ( $prefixOnly ) { - case 'delete': + // prefix only + return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=delete&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' ) ); - // delete page - if ( $objTypeID > 0 ){ + } + } // / got objType + break; + case 'tags': + // Tag manager page (returns for all obj types) + if ( $objTypeID > 0 ) { - if ( $id > 0 ) { + return esc_url_raw( admin_url( 'admin.php?page=' . $zbs->slugs['tagmanager'] . '&tagtype=' . $zbs->DAL->objTypeKey( $objTypeID ) ) ); - // view with actual ID - return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=delete&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID ) . '&zbsid=' . $id ) ); + } // / got objType - } else if ($prefixOnly){ + break; - // prefix only - return esc_url_raw( admin_url( 'admin.php?page=zbs-add-edit&action=delete&zbstype=' . $zbs->DAL->objTypeKey( $objTypeID).'&zbsid=' ) ); + case 'listtagged': + // List view -> tagged (returns for all obj types) + if ( $objTypeID > 0 ) { - } + // exception: event tags + if ( $objTypeID == ZBS_TYPE_TASK ) { - } // / got objType - break; - case 'tags': + return esc_url_raw( admin_url( 'admin.php?page=' . $zbs->slugs['manage-tasks-list'] . ( is_string( $taxonomy ) ? '&zbs_tag=' . $taxonomy : '' ) ) ); - // Tag manager page (returns for all obj types) - if ( $objTypeID > 0 ){ + } - return esc_url_raw( admin_url( 'admin.php?page=' . $zbs->slugs['tagmanager'] . '&tagtype=' . $zbs->DAL->objTypeKey( $objTypeID ) ) ); + return esc_url_raw( admin_url( 'admin.php?page=' . $zbs->DAL->listViewSlugFromObjID( $objTypeID ) . ( is_string( $taxonomy ) ? '&zbs_tag=' . $taxonomy : '' ) ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - } // / got objType + } // / got objType + break; - break; + case 'email': + switch ( $objTypeID ) { - case 'listtagged': + case ZBS_TYPE_CONTACT: + if ( $id > 0 ) { - // List view -> tagged (returns for all obj types) - if ( $objTypeID > 0 ){ + // email with actual ID + return esc_url_raw( zeroBSCRM_getAdminURL( $zbs->slugs['emails'] ) . '&zbsprefill=' . $id ); - // exception: event tags - if ( $objTypeID == ZBS_TYPE_TASK ) { + } elseif ( $prefixOnly ) { - return esc_url_raw( admin_url( 'admin.php?page=' . $zbs->slugs['manage-tasks-list'] . ( is_string( $taxonomy ) ? '&zbs_tag=' . $taxonomy : '' ) ) ); + // page only + return esc_url_raw( zeroBSCRM_getAdminURL( $zbs->slugs['emails'] ) . '&zbsprefill=' ); } - return esc_url_raw( admin_url( 'admin.php?page=' . $zbs->DAL->listViewSlugFromObjID( $objTypeID ) . ( is_string( $taxonomy ) ? '&zbs_tag=' . $taxonomy : '' ) ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + break; - } // / got objType - break; + } - case 'email': + break; - switch ( $objTypeID ){ + } - case ZBS_TYPE_CONTACT: + // if $key isn't in switch, assume it's a slug :) + return esc_url_raw( admin_url( 'admin.php?page=' . $key ) ); - if ($id > 0) { + // none? DASH then! + // return esc_url_raw( admin_url('admin.php?page=zerobscrm-dash') ); +} - // email with actual ID - return esc_url_raw( zeroBSCRM_getAdminURL( $zbs->slugs['emails'] ) . '&zbsprefill=' . $id ); +#} This is run by main init :) (Installs Quote Templates etc.) +function zeroBSCRM_installDefaultContent() { - } else if ( $prefixOnly ){ + global $zbs; - // page only - return esc_url_raw( zeroBSCRM_getAdminURL( $zbs->slugs['emails'] ) . '&zbsprefill=' ); + #} Quote Builder, defaults + $quoteBuilderDefaultsInstalled = zeroBSCRM_getSetting( 'quotes_default_templates' ); - } - - break; + if ( ! is_array( $quoteBuilderDefaultsInstalled ) ) { - } + #} Need installing! + $installedQuoteTemplates = array(); - break; + #} Load content + $quoteBuilderDefaultTemplates = array(); + #} Web Design: Example + $templatedHTML = file_get_contents( ZEROBSCRM_PATH . 'html/quotes/quote-template-web-design.html' ); + if ( ! empty( $templatedHTML ) ) { + $quoteBuilderDefaultTemplates['webdesignexample'] = array( + 'title' => __( 'Web Design: Example', 'zero-bs-crm' ), + 'html' => $templatedHTML, + 'value' => 500.00, + ); } - - - // if $key isn't in switch, assume it's a slug :) - return esc_url_raw( admin_url( 'admin.php?page=' . $key ) ); - - // none? DASH then! - // return esc_url_raw( admin_url('admin.php?page=zerobscrm-dash') ); - } - - #} This is run by main init :) (Installs Quote Templates etc.) - function zeroBSCRM_installDefaultContent() { - - global $zbs; - - #} Quote Builder, defaults - $quoteBuilderDefaultsInstalled = zeroBSCRM_getSetting('quotes_default_templates'); - if (!is_array($quoteBuilderDefaultsInstalled)){ - - #} Need installing! - $installedQuoteTemplates = array(); - - #} Load content - $quoteBuilderDefaultTemplates = array(); - - #} Web Design: Example - $templatedHTML = file_get_contents(ZEROBSCRM_PATH.'html/quotes/quote-template-web-design.html'); - if (!empty($templatedHTML)) $quoteBuilderDefaultTemplates['webdesignexample'] = array( - 'title' => __('Web Design: Example','zero-bs-crm'), - 'html' => $templatedHTML, - 'value' => 500.00 - ); - - - #} Install.. - if (count($quoteBuilderDefaultTemplates) > 0) foreach ($quoteBuilderDefaultTemplates as $template){ + #} Install.. + if ( count( $quoteBuilderDefaultTemplates ) > 0 ) { + foreach ( $quoteBuilderDefaultTemplates as $template ) { // Insert via DAL3 - $newTemplateID = $zbs->DAL->quotetemplates->addUpdateQuotetemplate(array( - // fields (directly) - 'data' => array( - - 'title' => $template['title'], - 'value' => $template['value'], - 'date_str' => '', - 'date' => '', - 'content' => $template['html'], - 'notes' => '', - 'currency' => '', - 'created' => time(), - 'lastupdated' => time(), - - - ), + $newTemplateID = $zbs->DAL->quotetemplates->addUpdateQuotetemplate( + array( + // fields (directly) + 'data' => array( + + 'title' => $template['title'], + 'value' => $template['value'], + 'date_str' => '', + 'date' => '', + 'content' => $template['html'], + 'notes' => '', + 'currency' => '', + 'created' => time(), + 'lastupdated' => time(), - 'extraMeta' => array('zbsdefault'=>1) - )); + ), - if ($newTemplateID > 0) $installedQuoteTemplates[] = $newTemplateID; + 'extraMeta' => array( 'zbsdefault' => 1 ), + ) + ); + if ( $newTemplateID > 0 ) { + $installedQuoteTemplates[] = $newTemplateID; + } } - - #} Log installed - $zbs->settings->update('quotes_default_templates',$installedQuoteTemplates); - } - + #} Log installed + $zbs->settings->update( 'quotes_default_templates', $installedQuoteTemplates ); } +} -/* ====================================================== - / General/WP helpers - ====================================================== */ +/* +====================================================== + / General/WP helpers +====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Addresses.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Addresses.php index f9061749bd06..c299f576b27e 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Addresses.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Addresses.php @@ -1,5 +1,5 @@ -> 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..b4d26973563f 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Companies.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Companies.php @@ -1,5 +1,5 @@ -> 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', - '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', - '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 ============= + '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, + ), + '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, + '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 +376,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,893 +451,970 @@ 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; + + } + } + } - #} 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; + // Calculate total vals etc. with SQL + if ( ! $simplified && ! $count && $withValues && ! $onlyColumns ) { - #} onlyColumns override - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + // 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 :) - $columnStr = ''; - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + // 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(); - if (!empty($columnStr)) $columnStr .= ','; - // this presumes str is db-safe? could do with sanitation? - $columnStr .= $colDBKey; + // 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: - $query = "SELECT ".$columnStr." FROM ".$ZBSCRM_t['companies'].' as company'.$joinQ; + ========== - } + SELECT * FROM wp_zbs_transactions trans + WHERE trans.ID IN - #} ============= WHERE ================ + ( + 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 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.'%'); + 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 - // 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.'%'); - } + */ + $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'; + } + + // ==== / TOTAL VALUES - // 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'])){ + #} ============ / PRE-QUERY =========== - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + #} Build query + $query = 'SELECT company.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['companies'] . ' as company' . $joinQ; - } + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(company.ID) FROM ' . $ZBSCRM_t['companies'] . ' as company' . $joinQ; + } - } - - #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) - if (is_array($inArr) && count($inArr) > 0){ + #} 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; + } - // clean for ints - $inArrChecked = array(); foreach ($inArr as $x){ $inArrChecked[] = (int)$x; } + #} onlyColumns override + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - // add where - $wheres['inarray'] = array('ID','IN','('.implode(',',$inArrChecked).')'); + $columnStr = ''; + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - } + if ( ! empty( $columnStr ) ) { + $columnStr .= ','; + } + // this presumes str is db-safe? could do with sanitation? + $columnStr .= $colDBKey; - #} 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); + } - } + $query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['companies'] . ' as company' . $joinQ; - // 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); + #} ============= 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 . '%' ); - } + } + + // 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'] ); + + } + } + + #} 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 ) . ')' ); + + } - // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed + #} 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 ); + + } + + // 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 ); + + } + + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable // quick addition for mike #} olderThan - if ( ! empty( $olderThan ) && $olderThan > 0 ) $wheres['olderThan'] = array( 'zbsco_created', '<=', '%d', $olderThan ); + if ( ! empty( $olderThan ) && $olderThan > 0 ) { + $wheres['olderThan'] = array( 'zbsco_created', '<=', '%d', $olderThan ); + } #} newerThan - if ( ! empty( $newerThan ) && $newerThan > 0 ) $wheres['newerThan'] = array( 'zbsco_created', '>=', '%d', $newerThan ); + if ( ! empty( $newerThan ) && $newerThan > 0 ) { + $wheres['newerThan'] = array( 'zbsco_created', '>=', '%d', $newerThan ); + } // status - if ( ! empty( $hasStatus ) ) $wheres['hasStatus'] = array( 'zbsco_status', '=', '%s', $hasStatus ); - if ( ! empty( $otherStatus ) ) $wheres['otherStatus'] = array( 'zbsco_status', '<>', '%s', $otherStatus ); + if ( ! empty( $hasStatus ) ) { + $wheres['hasStatus'] = array( 'zbsco_status', '=', '%s', $hasStatus ); + } + if ( ! empty( $otherStatus ) ) { + $wheres['otherStatus'] = array( 'zbsco_status', '<>', '%s', $otherStatus ); + } #} inCounty if ( ! empty( $inCounty ) ) { @@ -1317,8 +1448,13 @@ 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)' ); - + 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 @@ -1336,16 +1472,16 @@ public function getCompanies($args=array()){ $wheres['isLinkedToObjID'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objtype_to = %d AND zbsol_objid_from = company.ID AND zbsol_objid_to = %d)', array( $isLinkedToObjType, $isLinkedToObjID ) ); } - // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - #} 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 +1489,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 +1626,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 ) ) { - - $sortByField = $sort_map[ $sortByField ]; + ); - } + if ( array_key_exists( $sortByField, $sort_map ) ) { - #} ============ / SORT ============== + $sortByField = $sort_map[ $sortByField ]; - #} 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 + #} ============ / SORT ============== - #} 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); - - try { + #} 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 - #} 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) { - - #} simplified override - if ($simplified){ + } - $resArr = array( - 'id' => $resDataLine->id, - 'name' => $resDataLine->name, - 'created' => $resDataLine->created, - 'email' => $resDataLine->email - ); + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - } else if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - // only coumns return. - $resArr = array(); - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + #} simplified override + if ( $simplified ) { - if (isset($resDataLine->$colDBKey)) $resArr[$colStr] = $resDataLine->$colDBKey; + $resArr = array( + 'id' => $resDataLine->id, + 'name' => $resDataLine->name, + 'created' => $resDataLine->created, + 'email' => $resDataLine->email, + ); - } + } elseif ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { + // only coumns return. + $resArr = array(); + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - } else { - - // tidy - $resArr = $this->tidy_company($resDataLine,$withCustomFields); + if ( isset( $resDataLine->$colDBKey ) ) { + $resArr[ $colStr ] = $resDataLine->$colDBKey; + } + } + } else { - } + // tidy + $resArr = $this->tidy_company( $resDataLine, $withCustomFields ); - if ($withTags){ + } - // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_COMPANY,'objid'=>$resDataLine->ID)); + if ( $withTags ) { - } + // 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){ + } - // doesn't return singular, for now using arr - $potentialLogs = $this->DAL()->logs->getLogsForObj(array( + #} With most recent log? #DB1LEGACY (TOMOVE) + if ( $withLastLog ) { - 'objtype' => ZBS_TYPE_COMPANY, - 'objid' => $resDataLine->ID, - - 'incMeta' => true, + // doesn't return singular, for now using arr + $potentialLogs = $this->DAL()->logs->getLogsForObj( + array( - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1 + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $resDataLine->ID, - )); + 'incMeta' => true, - if (is_array($potentialLogs) && count($potentialLogs) > 0) $resArr['lastlog'] = $potentialLogs[0]; + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, - // 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 + if ( is_array( $potentialLogs ) && count( $potentialLogs ) > 0 ) { + $resArr['lastlog'] = $potentialLogs[0]; + } - 'notetypes' => $zbs->DAL->logs->contact_log_types, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + // COMPANY logs specifically + // doesn't return singular, for now using arr + $potentialLogs = $this->DAL()->logs->getLogsForObj( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + array( - 'incMeta' => true, + 'objtype' => ZBS_TYPE_COMPANY, + 'objid' => $resDataLine->ID, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1, + 'notetypes' => $zbs->DAL->logs->contact_log_types, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - ) - ); + 'incMeta' => true, - if (is_array($potentialLogs) && count($potentialLogs) > 0) $resArr['lastcontactlog'] = $potentialLogs[0]; + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, - } + ) + ); - #} 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; + public function getCompanyEmail( $id = -1 ) { - $id = (int)$id; - - 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.Contacts.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Contacts.php index a467054d2f84..12db443fd9e5 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Contacts.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Contacts.php @@ -1,5 +1,6 @@ -> Contacts -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Contacts + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_contacts extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_CONTACT; - protected $objectDBPrefix = 'zbsc_'; - protected $objectIncludesAddresses = true; - protected $include_in_templating = true; + protected $objectType = ZBS_TYPE_CONTACT; + protected $objectDBPrefix = 'zbsc_'; + protected $objectIncludesAddresses = true; + protected $include_in_templating = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase, Squiz.Commenting.VariableComment.Missing -- to be refactored. protected $objectModel = array(); /** @var Events_Manager To manage the CRM events */ private $events_manager; - // hardtyped list of types this object type is commonly linked to - protected $linkedToObjectTypes = array( - - ZBS_TYPE_COMPANY - - ); - - // phpcs:ignore Squiz.Commenting.FunctionComment.Missing, Squiz.Scope.MethodScope.Missing -- to be refactored. - function __construct( $args = array() ) { - // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- to be refactored. - $this->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' => 'zbsc_status', - 'format' => 'str', - // output model - 'input_type' => 'select', - 'label' => __( 'Status', 'zero-bs-crm' ), - 'placeholder' => '', - 'options' => array( 'Lead', 'Customer', 'Refused' ), - 'essential' => true, - 'max_len' => 100, - 'do_not_show_on_portal' => true, - ), - 'email' => array( - // db model: - 'fieldname' => 'zbsc_email', - 'format' => 'str', - // output model - 'input_type' => 'email', - 'label' => __( 'Email', 'zero-bs-crm' ), - 'placeholder' => 'e.g. john@gmail.com', - 'essential' => true, - 'force_unique' => true, // must be unique. This is required and breaking if true - 'can_be_blank' => true, - 'max_len' => 200, - // removed due to some users using mobile/other as unique field? see #gh-153 - // 'not_empty' => true, - 'do_not_show_on_portal' => true, - ), - 'prefix' => array( - // db model: - 'fieldname' => 'zbsc_prefix', - 'format' => 'str', - // output model - 'input_type' => 'select', - 'label' => __( 'Prefix', 'zero-bs-crm' ), - 'placeholder' => '', - 'options' => array( 'Mr', 'Mrs', 'Ms', 'Miss', 'Mx', 'Dr', 'Prof', 'Mr & Mrs' ), - 'essential' => true, - 'max_len' => 30, - ), - 'fname' => array( - // db model: - 'fieldname' => 'zbsc_fname', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'First Name', 'zero-bs-crm' ), - 'placeholder' => 'e.g. John', - 'essential' => true, - 'max_len' => 100, - ), - 'lname' => array( - // db model: - 'fieldname' => 'zbsc_lname', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'Last Name', 'zero-bs-crm' ), - 'placeholder' => 'e.g. Doe', - 'essential' => true, - 'max_len' => 100, - ), - - 'addr1' => array( - // db model: - 'fieldname' => 'zbsc_addr1', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'Address Line 1', 'zero-bs-crm' ), - 'placeholder' => '', - 'area' => 'Main Address', - 'migrate' => 'addresses', - 'max_len' => 200, - ), - 'addr2' => array( - // db model: - 'fieldname' => 'zbsc_addr2', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'Address Line 2', 'zero-bs-crm' ), - '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', 'zero-bs-crm' ), - 'placeholder' => 'e.g. New York', - 'area' => 'Main Address', - 'migrate' => 'addresses', - 'max_len' => 200, - ), - 'county' => array( - // db model: - 'fieldname' => 'zbsc_county', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'County', 'zero-bs-crm' ), - 'placeholder' => 'e.g. Kings County', - 'area' => 'Main Address', - 'migrate' => 'addresses', - 'max_len' => 200, - ), - 'postcode' => array( - // db model: - 'fieldname' => 'zbsc_postcode', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'Post Code', 'zero-bs-crm' ), - 'placeholder' => 'e.g. 10019', - 'area' => 'Main Address', - 'migrate' => 'addresses', - 'max_len' => 50, - ), - 'country' => array( - // db model: - 'fieldname' => 'zbsc_country', - 'format' => 'str', - // output model - 'input_type' => 'selectcountry', - 'label' => __( 'Country', 'zero-bs-crm' ), - 'placeholder' => '', - 'area' => 'Main Address', - 'migrate' => 'addresses', - 'max_len' => 200, - ), - 'secaddr1' => array( - // db model: - 'fieldname' => 'zbsc_addr1', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'Address Line 1', 'zero-bs-crm' ), - 'placeholder' => '', - 'area' => 'Second Address', - 'migrate' => 'addresses', - 'opt' => 'secondaddress', - 'max_len' => 200, - 'dal1key' => 'secaddr_addr1', // previous field name - ), - 'secaddr2' => array( - // db model: - 'fieldname' => 'zbsc_addr2', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'Address Line 2', 'zero-bs-crm' ), - 'placeholder' => '', - 'area' => 'Second Address', - 'migrate' => 'addresses', - 'opt' => 'secondaddress', - 'max_len' => 200, - 'dal1key' => 'secaddr_addr2', // previous field name - ), - 'seccity' => array( - // db model: - 'fieldname' => 'zbsc_city', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'City', 'zero-bs-crm' ), - 'placeholder' => 'e.g. Los Angeles', - 'area' => 'Second Address', - 'migrate' => 'addresses', - 'opt' => 'secondaddress', - 'max_len' => 200, - 'dal1key' => 'secaddr_city', // previous field name - ), - 'seccounty' => array( - // db model: - 'fieldname' => 'zbsc_county', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'County', 'zero-bs-crm' ), - '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' => 'zbsc_postcode', - 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => __( 'Post Code', 'zero-bs-crm' ), - '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' => 'zbsc_country', - 'format' => 'str', - // output model - 'input_type' => 'selectcountry', - 'label' => __( 'Country', 'zero-bs-crm' ), - 'placeholder' => '', - 'area' => 'Second Address', - 'migrate' => 'addresses', - 'opt' => 'secondaddress', - 'max_len' => 200, - 'dal1key' => 'secaddr_country', // previous field name - ), - 'hometel' => array( - // db model: - 'fieldname' => 'zbsc_hometel', - 'format' => 'str', - // output model - 'input_type' => 'tel', - 'label' => __( 'Home Telephone', 'zero-bs-crm' ), - 'placeholder' => 'e.g. 877 2733049', - 'max_len' => 40, - ), - 'worktel' => array( - // db model: - 'fieldname' => 'zbsc_worktel', - 'format' => 'str', - // output model - 'input_type' => 'tel', - 'label' => __( 'Work Telephone', 'zero-bs-crm' ), - 'placeholder' => 'e.g. 877 2733049', - 'max_len' => 40, - ), - 'mobtel' => array( - // db model: - 'fieldname' => 'zbsc_mobtel', - 'format' => 'str', - // output model - 'input_type' => 'tel', - 'label' => __( 'Mobile Telephone', 'zero-bs-crm' ), - 'placeholder' => 'e.g. 877 2733050', - 'max_len' => 40, - ), - - // ... just removed for DAL3 :) should be custom field anyway by this point - - 'wpid' => array( - // db model: - 'fieldname' => 'zbsc_wpid', - 'format' => 'int', - // output model - // NONE, not exposed via standard input - ), - 'avatar' => array( - // db model: - 'fieldname' => 'zbsc_avatar', - 'format' => 'str', - // output model - // NONE, not exposed via standard input - ), - 'tw' => array( - // db model: - 'fieldname' => 'zbsc_tw', - 'format' => 'str', - 'max_len' => 100, - // output model - // NONE, not exposed via standard input - ), - 'li' => array( - // db model: - 'fieldname' => 'zbsc_li', - 'format' => 'str', - 'max_len' => 300, - // output model - // NONE, not exposed via standard input - ), - 'fb' => array( - // db model: - 'fieldname' => 'zbsc_fb', - 'format' => 'str', - 'max_len' => 200, - // output model - // NONE, not exposed via standard input - ), - 'created' => array( - // db model: - 'fieldname' => 'zbsc_created', - 'format' => 'uts', - // output model - // NONE, not exposed via db - ), - 'lastupdated' => array( - // db model: - 'fieldname' => 'zbsc_lastupdated', - 'format' => 'uts', - // output model - // NONE, not exposed via db - ), - 'lastcontacted' => array( - // db model: - 'fieldname' => 'zbsc_lastcontacted', - 'format' => 'uts', - // output model - // NONE, not exposed via db - ), + // hardtyped list of types this object type is commonly linked to + protected $linkedToObjectTypes = array( + + ZBS_TYPE_COMPANY, + + ); + + // phpcs:ignore Squiz.Commenting.FunctionComment.Missing, Squiz.Scope.MethodScope.Missing -- to be refactored. + function __construct( $args = array() ) { + // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- to be refactored. + $this->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' => 'zbsc_status', + 'format' => 'str', + // output model + 'input_type' => 'select', + 'label' => __( 'Status', 'zero-bs-crm' ), + 'placeholder' => '', + 'options' => array( 'Lead', 'Customer', 'Refused' ), + 'essential' => true, + 'max_len' => 100, + 'do_not_show_on_portal' => true, + ), + 'email' => array( + // db model: + 'fieldname' => 'zbsc_email', + 'format' => 'str', + // output model + 'input_type' => 'email', + 'label' => __( 'Email', 'zero-bs-crm' ), + 'placeholder' => 'e.g. john@gmail.com', + 'essential' => true, + 'force_unique' => true, // must be unique. This is required and breaking if true + 'can_be_blank' => true, + 'max_len' => 200, + // removed due to some users using mobile/other as unique field? see #gh-153 + // 'not_empty' => true, + 'do_not_show_on_portal' => true, + ), + 'prefix' => array( + // db model: + 'fieldname' => 'zbsc_prefix', + 'format' => 'str', + // output model + 'input_type' => 'select', + 'label' => __( 'Prefix', 'zero-bs-crm' ), + 'placeholder' => '', + 'options' => array( 'Mr', 'Mrs', 'Ms', 'Miss', 'Mx', 'Dr', 'Prof', 'Mr & Mrs' ), + 'essential' => true, + 'max_len' => 30, + ), + 'fname' => array( + // db model: + 'fieldname' => 'zbsc_fname', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'First Name', 'zero-bs-crm' ), + 'placeholder' => 'e.g. John', + 'essential' => true, + 'max_len' => 100, + ), + 'lname' => array( + // db model: + 'fieldname' => 'zbsc_lname', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'Last Name', 'zero-bs-crm' ), + 'placeholder' => 'e.g. Doe', + 'essential' => true, + 'max_len' => 100, + ), + + 'addr1' => array( + // db model: + 'fieldname' => 'zbsc_addr1', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'Address Line 1', 'zero-bs-crm' ), + 'placeholder' => '', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 200, + ), + 'addr2' => array( + // db model: + 'fieldname' => 'zbsc_addr2', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'Address Line 2', 'zero-bs-crm' ), + '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', 'zero-bs-crm' ), + 'placeholder' => 'e.g. New York', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 200, + ), + 'county' => array( + // db model: + 'fieldname' => 'zbsc_county', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'County', 'zero-bs-crm' ), + 'placeholder' => 'e.g. Kings County', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 200, + ), + 'postcode' => array( + // db model: + 'fieldname' => 'zbsc_postcode', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'Post Code', 'zero-bs-crm' ), + 'placeholder' => 'e.g. 10019', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 50, + ), + 'country' => array( + // db model: + 'fieldname' => 'zbsc_country', + 'format' => 'str', + // output model + 'input_type' => 'selectcountry', + 'label' => __( 'Country', 'zero-bs-crm' ), + 'placeholder' => '', + 'area' => 'Main Address', + 'migrate' => 'addresses', + 'max_len' => 200, + ), + 'secaddr1' => array( + // db model: + 'fieldname' => 'zbsc_addr1', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'Address Line 1', 'zero-bs-crm' ), + 'placeholder' => '', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 200, + 'dal1key' => 'secaddr_addr1', // previous field name + ), + 'secaddr2' => array( + // db model: + 'fieldname' => 'zbsc_addr2', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'Address Line 2', 'zero-bs-crm' ), + 'placeholder' => '', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 200, + 'dal1key' => 'secaddr_addr2', // previous field name + ), + 'seccity' => array( + // db model: + 'fieldname' => 'zbsc_city', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'City', 'zero-bs-crm' ), + 'placeholder' => 'e.g. Los Angeles', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 200, + 'dal1key' => 'secaddr_city', // previous field name + ), + 'seccounty' => array( + // db model: + 'fieldname' => 'zbsc_county', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'County', 'zero-bs-crm' ), + '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' => 'zbsc_postcode', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => __( 'Post Code', 'zero-bs-crm' ), + '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' => 'zbsc_country', + 'format' => 'str', + // output model + 'input_type' => 'selectcountry', + 'label' => __( 'Country', 'zero-bs-crm' ), + 'placeholder' => '', + 'area' => 'Second Address', + 'migrate' => 'addresses', + 'opt' => 'secondaddress', + 'max_len' => 200, + 'dal1key' => 'secaddr_country', // previous field name + ), + 'hometel' => array( + // db model: + 'fieldname' => 'zbsc_hometel', + 'format' => 'str', + // output model + 'input_type' => 'tel', + 'label' => __( 'Home Telephone', 'zero-bs-crm' ), + 'placeholder' => 'e.g. 877 2733049', + 'max_len' => 40, + ), + 'worktel' => array( + // db model: + 'fieldname' => 'zbsc_worktel', + 'format' => 'str', + // output model + 'input_type' => 'tel', + 'label' => __( 'Work Telephone', 'zero-bs-crm' ), + 'placeholder' => 'e.g. 877 2733049', + 'max_len' => 40, + ), + 'mobtel' => array( + // db model: + 'fieldname' => 'zbsc_mobtel', + 'format' => 'str', + // output model + 'input_type' => 'tel', + 'label' => __( 'Mobile Telephone', 'zero-bs-crm' ), + 'placeholder' => 'e.g. 877 2733050', + 'max_len' => 40, + ), + + // ... just removed for DAL3 :) should be custom field anyway by this point + + 'wpid' => array( + // db model: + 'fieldname' => 'zbsc_wpid', + 'format' => 'int', + // output model + // NONE, not exposed via standard input + ), + 'avatar' => array( + // db model: + 'fieldname' => 'zbsc_avatar', + 'format' => 'str', + // output model + // NONE, not exposed via standard input + ), + 'tw' => array( + // db model: + 'fieldname' => 'zbsc_tw', + 'format' => 'str', + 'max_len' => 100, + // output model + // NONE, not exposed via standard input + ), + 'li' => array( + // db model: + 'fieldname' => 'zbsc_li', + 'format' => 'str', + 'max_len' => 300, + // output model + // NONE, not exposed via standard input + ), + 'fb' => array( + // db model: + 'fieldname' => 'zbsc_fb', + 'format' => 'str', + 'max_len' => 200, + // output model + // NONE, not exposed via standard input + ), + 'created' => array( + // db model: + 'fieldname' => 'zbsc_created', + 'format' => 'uts', + // output model + // NONE, not exposed via db + ), + 'lastupdated' => array( + // db model: + 'fieldname' => 'zbsc_lastupdated', + 'format' => 'uts', + // output model + // NONE, not exposed via db + ), + 'lastcontacted' => array( + // db model: + 'fieldname' => 'zbsc_lastcontacted', + 'format' => 'uts', + // output model + // NONE, not exposed via db + ), + ); + + #} =========== 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 ============= + + $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. + * + * @param array $listview_filters Listview filters. + */ + public function add_listview_filters( $listview_filters ) { + global $zbs; + + // Add "assigned"/"not assigned" filters. + $listview_filters[ ZBS_TYPE_CONTACT ]['general']['assigned_to_me'] = __( 'Assigned to me', 'zero-bs-crm' ); + $listview_filters[ ZBS_TYPE_CONTACT ]['general']['not_assigned'] = __( 'Not assigned', 'zero-bs-crm' ); + + $quick_filter_settings = $zbs->settings->get( 'quickfiltersettings' ); + + // Add 'not-contacted-in-x-days'. + if ( ! empty( $quick_filter_settings['notcontactedinx'] ) && $quick_filter_settings['notcontactedinx'] > 0 ) { + $days = (int) $quick_filter_settings['notcontactedinx']; + $listview_filters[ ZBS_TYPE_CONTACT ]['general'][ 'notcontactedin' . $days ] = sprintf( + // translators: %s is the number of days + __( 'Not Contacted in %s days', 'zero-bs-crm' ), + $days ); + } - #} =========== 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 ============= - - $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. - * - * @param array $listview_filters Listview filters. - */ - public function add_listview_filters( $listview_filters ) { - global $zbs; - - // Add "assigned"/"not assigned" filters. - $listview_filters[ ZBS_TYPE_CONTACT ]['general']['assigned_to_me'] = __( 'Assigned to me', 'zero-bs-crm' ); - $listview_filters[ ZBS_TYPE_CONTACT ]['general']['not_assigned'] = __( 'Not assigned', 'zero-bs-crm' ); - - $quick_filter_settings = $zbs->settings->get( 'quickfiltersettings' ); + // Add 'olderthan-x-days'. + if ( ! empty( $quick_filter_settings['olderthanx'] ) && $quick_filter_settings['olderthanx'] > 0 ) { + $days = (int) $quick_filter_settings['olderthanx']; + $listview_filters[ ZBS_TYPE_CONTACT ]['general'][ 'olderthan' . $days ] = sprintf( + // translators: %s is the number of days + __( 'Older than %s days', 'zero-bs-crm' ), + $days + ); + } - // Add 'not-contacted-in-x-days'. - if ( ! empty( $quick_filter_settings['notcontactedinx'] ) && $quick_filter_settings['notcontactedinx'] > 0 ) { - $days = (int) $quick_filter_settings['notcontactedinx']; - $listview_filters[ ZBS_TYPE_CONTACT ]['general'][ 'notcontactedin' . $days ] = sprintf( - // translators: %s is the number of days - __( 'Not Contacted in %s days', 'zero-bs-crm' ), - $days - ); + // Add statuses if enabled. + if ( $zbs->settings->get( 'filtersfromstatus' ) === 1 ) { + $statuses = zeroBSCRM_getCustomerStatuses( true ); + foreach ( $statuses as $status ) { + $listview_filters[ ZBS_TYPE_CONTACT ]['status'][ 'status_' . $status ] = $status; } + } - // Add 'olderthan-x-days'. - if ( ! empty( $quick_filter_settings['olderthanx'] ) && $quick_filter_settings['olderthanx'] > 0 ) { - $days = (int) $quick_filter_settings['olderthanx']; - $listview_filters[ ZBS_TYPE_CONTACT ]['general'][ 'olderthan' . $days ] = sprintf( - // translators: %s is the number of days - __( 'Older than %s days', 'zero-bs-crm' ), - $days - ); + // Add segments if enabled. + if ( $zbs->settings->get( 'filtersfromsegments' ) === 1 ) { + $segments = $zbs->DAL->segments->getSegments( -1, 100, 0, false, '', '', 'zbsseg_name', 'ASC' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + foreach ( $segments as $segment ) { + $listview_filters[ ZBS_TYPE_CONTACT ]['segment'][ 'segment_' . $segment['slug'] ] = $segment['name']; } + } - // Add statuses if enabled. - if ( $zbs->settings->get( 'filtersfromstatus' ) === 1 ) { - $statuses = zeroBSCRM_getCustomerStatuses( true ); - foreach ( $statuses as $status ) { - $listview_filters[ ZBS_TYPE_CONTACT ]['status'][ 'status_' . $status ] = $status; + 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->getContact( $ID ); + } + + // generic get contact (by ID list) + // Super simplistic wrapper used by MVP Export v3.0 + public function getIDList( $IDs = false ) { + + return $this->getContacts( + array( + 'inArr' => $IDs, + 'withCustomFields' => true, + 'withValues' => true, + 'withAssigned' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + // generic get (EVERYTHING) + // expect heavy load! + public function getAll( $IDs = false ) { + + return $this->getContacts( + array( + 'withCustomFields' => true, + 'withValues' => true, + 'withAssigned' => true, + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + // generic get count of (EVERYTHING) + public function getFullCount() { + + return $this->getContacts( + array( + 'count' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + /* + * Returns an (int) count of all contacts with an external source + */ + public function getTotalExtSourceCount() { + + global $ZBSCRM_t, $wpdb; + + $query = 'SELECT COUNT(contacts.id) FROM ' . $ZBSCRM_t['contacts'] . ' contacts' + . ' INNER JOIN ' . $ZBSCRM_t['externalsources'] . ' ext_sources' + . ' ON contacts.id = ext_sources.zbss_objid' + . ' WHERE ext_sources.zbss_objtype = ' . ZBS_TYPE_CONTACT; + + /* + SELECT COUNT(contacts.id) FROM + wp_zbs_contacts contacts + INNER JOIN wp_zbs_externalsources ext_sources + ON contacts.id = ext_sources.zbss_objid + WHERE ext_sources.zbss_objtype = 1 + */ + + return $wpdb->get_var( $query ); + } + + /** + * returns full contact line +- details + * Replaces many funcs, inc zeroBS_getCustomerIDFromWPID, zeroBS_getCustomerIDWithEmail etc. + * + * @param int id contact id + * @param array $args Associative array of arguments + * withQuotes, withInvoices, withTransactions, withLogs + * + * @return array result + */ + public function getContact( $id = -1, $args = array() ) { + + global $zbs; + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + 'email' => false, // if id -1 and email given, will return based on email search + 'WPID' => false, // if id -1 and wpid given, will return based on wpid search + + // 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, + 'withCompanies' => false, + 'withOwner' => false, + 'withValues' => false, // if passed, returns with 'total' 'invoices_total' 'transactions_total' etc. (requires getting all obj, use sparingly) + 'withAliases' => false, + 'withExternalSources' => false, + 'withExternalSourcesGrouped' => false, + + 'with_obj_limit' => false, // if (int) specified, this will limit the count of quotes, invoices, transactions, and tasks returned + + // permissions + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), // 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( $WPID ) && $WPID > 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_CONTACT ) ); + + #} 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 = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '" . $cK . "'"; + + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_CONTACT; - // Add segments if enabled. - if ( $zbs->settings->get( 'filtersfromsegments' ) === 1 ) { - $segments = $zbs->DAL->segments->getSegments( -1, 100, 0, false, '', '', 'zbsseg_name', 'ASC' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - foreach ( $segments as $segment ) { - $listview_filters[ ZBS_TYPE_CONTACT ]['segment'][ 'segment_' . $segment['slug'] ] = $segment['name']; + } } } - 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->getContact($ID); - - } - - // generic get contact (by ID list) - // Super simplistic wrapper used by MVP Export v3.0 - public function getIDList($IDs=false){ - - return $this->getContacts(array( - 'inArr' => $IDs, - 'withCustomFields' => true, - 'withValues' => true, - 'withAssigned' => true, - 'page' => -1, - 'perPage' => -1 - )); - - } - - // generic get (EVERYTHING) - // expect heavy load! - public function getAll($IDs=false){ - - return $this->getContacts(array( - 'withCustomFields' => true, - 'withValues' => true, - 'withAssigned' => true, - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => -1, - 'perPage' => -1, - )); - - } - - // generic get count of (EVERYTHING) - public function getFullCount(){ - - return $this->getContacts(array( - 'count' => true, - 'page' => -1, - 'perPage' => -1, - )); - - } - - /* - * Returns an (int) count of all contacts with an external source - */ - public function getTotalExtSourceCount(){ - - global $ZBSCRM_t,$wpdb; - - $query = "SELECT COUNT(contacts.id) FROM " . $ZBSCRM_t['contacts'] . " contacts" - . " INNER JOIN " . $ZBSCRM_t['externalsources'] . " ext_sources" - . " ON contacts.id = ext_sources.zbss_objid" - . " WHERE ext_sources.zbss_objtype = " . ZBS_TYPE_CONTACT; - - /* - SELECT COUNT(contacts.id) FROM - wp_zbs_contacts contacts - INNER JOIN wp_zbs_externalsources ext_sources - ON contacts.id = ext_sources.zbss_objid - WHERE ext_sources.zbss_objtype = 1 - */ - - return $wpdb->get_var( $query ); - - } - - /** - * returns full contact line +- details - * Replaces many funcs, inc zeroBS_getCustomerIDFromWPID, zeroBS_getCustomerIDWithEmail etc. - * - * @param int id contact id - * @param array $args Associative array of arguments - * withQuotes, withInvoices, withTransactions, withLogs - * - * @return array result - */ - public function getContact($id=-1,$args=array()){ - - global $zbs; - - #} =========== LOAD ARGS ============== - $defaultArgs = array( - - 'email' => false, // if id -1 and email given, will return based on email search - 'WPID' => false, // if id -1 and wpid given, will return based on wpid search - - // 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, - 'withCompanies' => false, - 'withOwner' => false, - 'withValues' => false, // if passed, returns with 'total' 'invoices_total' 'transactions_total' etc. (requires getting all obj, use sparingly) - 'withAliases' => false, - 'withExternalSources' => false, - 'withExternalSourcesGrouped' => false, - - 'with_obj_limit' => false, // if (int) specified, this will limit the count of quotes, invoices, transactions, and tasks returned - - // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT), // 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($WPID) && $WPID > 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_CONTACT)); - - #} 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 = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '".$cK."'"; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_CONTACT; - - } - - } - - #} Aliases - if ($withAliases){ - - #} Retrieve these as a CSV :) - $extraSelect .= ',(SELECT ' . $this->DAL()->build_group_concat( 'aka_alias', ',' ) . ' FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_id = contact.ID) aliases'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - } - - // 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); - - // addr 1 - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey; - // add params - $params[] = $cfKey; $params[] = ZBS_TYPE_CONTACT; - // addr 2 - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey2; - // add params - $params[] = $cfKey2; $params[] = ZBS_TYPE_CONTACT; - - } - - - } - - // ==== TOTAL VALUES - - // Calculate total vals etc. with SQL - if ($withValues && !$onlyID){ - // only include transactions with statuses which should be included in total value: - $transStatusQueryAdd = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // 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_CONTACT." AND zbsol_objid_to = contact.ID)) as quotes_total"; - // invs not including deleted: - $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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT." AND zbsol_objid_to = contact.ID)".$transStatusQueryAdd.") as transactions_total"; - // paid balance against invs (also in getContacts) - // (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_CONTACT.' AND zbsol_objid_to = contact.ID)'; - $extraSelect .= ')'.$transStatusQueryAdd.') as transactions_paid_total'; - } - - // ==== / TOTAL VALUES - - $selector = 'contact.*'; - 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 = 'contact.ID'; - - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'contact.'.$f; - } - } else if ($onlyID){ - $selector = 'contact.ID'; - } - - #} ============ / PRE-QUERY =========== - - - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['contacts'].' as contact'; - #} ============= WHERE ================ - - if (!empty($id) && $id > 0){ - - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); - - } - - if (!empty($email)){ - - - // where we're seeking the ID from an email we can override the query for performance benefits (#gh-2450): - if ( $onlyID ){ - - $query = 'SELECT contact.ID FROM ( SELECT contact.ID FROM ' . $ZBSCRM_t['contacts'] . ' as contact WHERE zbsc_email = %s UNION ALL SELECT aka_id AS ID FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = 1 AND aka_alias = %s) contact'; - $wheres = array( 'direct' => array() ); - $params = array( $email, $email ); - - } else { - - $emailWheres = array(); - - #} Add ID - $emailWheres['emailcheck'] = array('zbsc_email','=','%s',$email); - - #} Check AKA - $emailWheres['email_alias'] = array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." 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'])){ - - // add it - $wheres['direct'][] = array('('.$emailSearchQueryArr['where'].')',$emailSearchQueryArr['params']); - - } - - } - - } - - if (!empty($WPID) && $WPID > 0){ - - #} Add ID - $wheres['WPID'] = array('zbsc_wpid','=','%d',$WPID); - - } - - if (!empty($externalSource) && !empty($externalSourceUID)){ - - $wheres['extsourcecheck'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_CONTACT." 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_contact($potentialRes,$withCustomFields); - } - - if ($withTags){ - - // add all tags lines - $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_CONTACT,'objid'=>$potentialRes->ID)); - - } - - // =================================================== - // ========== #} #DB1LEGACY (TOMOVE) - // == Following is all using OLD DB stuff, here until we migrate inv etc. - // =================================================== - - #} With most recent log? #DB1LEGACY (TOMOVE) - if ($withLastLog){ - - $res['lastlog'] = $this->DAL()->logs->getLogsForObj(array( - - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $potentialRes->ID, - - 'incMeta' => true, - - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1 - - )); - - } - - #} With Assigned? - if ($withOwner){ - - $res['owner'] = zeroBS_getOwner($potentialRes->ID,true,'zerobs_customer',$potentialRes->zbs_owner); - - } - - // Objects: return all, unless $with_obj_limit - $objs_page = -1; - $objs_per_page = -1; - $with_obj_limit = (int)$with_obj_limit; - if ( $with_obj_limit > 0 ){ - - $objs_page = 0; - $objs_per_page = $with_obj_limit; - - } - - - if ($withInvoices){ - - #} only gets first 100? - //DAL3 ver, more perf, gets all - $res['invoices'] = $zbs->DAL->invoices->getInvoices(array( - - 'assignedContact' => $potentialRes->ID, // assigned to company id (int) - 'page' => $objs_page, - 'perPage' => $objs_per_page, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE), - 'sortByField' => 'ID', - 'sortOrder' => 'DESC', - 'withAssigned' => false // no need, it's assigned to this obj already - - )); - - } - - if ($withQuotes){ - - //DAL3 ver, more perf, gets all - $res['quotes'] = $zbs->DAL->quotes->getQuotes(array( - - 'assignedContact' => $potentialRes->ID, // assigned to company id (int) - 'page' => $objs_page, - 'perPage' => $objs_per_page, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE), - 'sortByField' => 'ID', - 'sortOrder' => 'DESC', - 'withAssigned' => false // no need, it's assigned to this obj already - - )); - - } - - #} ... brutal for mvp #DB1LEGACY (TOMOVE) - if ($withTransactions){ - - //DAL3 ver, more perf, gets all - $res['transactions'] = $zbs->DAL->transactions->getTransactions(array( - - 'assignedContact' => $potentialRes->ID, // assigned to company id (int) - 'page' => $objs_page, - 'perPage' => $objs_per_page, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION), - 'sortByField' => 'ID', - 'sortOrder' => 'DESC', - 'withAssigned' => false // no need, it's assigned to this obj already - - )); - - } - - //} - - #} With co's? - if ($withCompanies){ - - // add all company lines - $res['companies'] = $this->DAL()->getObjsLinkedToObj(array( - 'objtypefrom' => ZBS_TYPE_CONTACT, // contact - 'objtypeto' => ZBS_TYPE_COMPANY, // company - 'objfromid' => $potentialRes->ID)); - - } - - #} ... brutal for mvp #DB1LEGACY (TOMOVE) - if ($withTasks){ - - //DAL3 ver, more perf, gets all - $res['tasks'] = $zbs->DAL->events->getEvents(array( - - 'assignedContact' => $potentialRes->ID, // assigned to company id (int) - 'page' => $objs_page, - 'perPage' => $objs_per_page, - '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->contacts->getExternalSourcesForContact(array( - - 'contactID'=> $potentialRes->ID, - - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) - - )); - - } - if ( $withExternalSourcesGrouped ){ - - $res['external_sources'] = $zbs->DAL->getExternalSources( -1, array( - - 'objectID' => $potentialRes->ID, - 'objectType' => ZBS_TYPE_CONTACT, - 'grouped_by_source' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) - - )); - - } - - // =================================================== - // ========== / #DB1LEGACY (TOMOVE) - // =================================================== - - - return $res; - - } - - } // / if ID - - return false; - - } - - // TODO $argsOverride=false - /** - * returns contact detail lines - * - * @param array $args Associative array of arguments - * withQuotes, withInvoices, withTransactions, withLogs, searchPhrase, sortByField, sortOrder, page, perPage - * - * @return array of contact lines - */ - public function getContacts($args=array()){ - - global $zbs; - - - #} ============ LOAD ARGS ============= - $defaultArgs = array( - - // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches which fields? - 'inCompany' => false, // will be an ID if used - 'inArr' => false, - 'quickFilters' => 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' - - // last contacted - 'contactedBefore' => false, // uts - 'contactedAfter' => false, // uts - - // email - 'hasEmail' => false, // 'x@y.com' either in main field or as AKA - - // 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, - 'onlyObjTotals' => false, // if passed, returns for group: 'total' 'invoices_total' 'transactions_total' etc. (requires getting a lot of objs, use sparingly) - 'withCustomFields' => true, - 'withQuotes' => false, - 'withInvoices' => false, - 'withTransactions' => false, - 'withTasks' => false, - 'withLogs' => false, - 'withLastLog' => false, - 'withTags' => false, - 'withOwner' => false, - 'withAssigned' => false, // return ['company'] objs if has link - 'withDND' => false, // if true, returns getContactDoNotMail as well :) - 'simplified' => false, // returns just id,name,created,email (for typeaheads) - 'withValues' => false, // if passed, returns with 'total' 'invoices_total' 'transactions_total' etc. (requires getting all obj, use sparingly) - '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) - 'withAliases' => false, - 'withExternalSources' => false, - 'withExternalSourcesGrouped' => false, - - - '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_CONTACT), // this'll let you not-check the owner of obj - - // 'argsOverride' => ?? Still req? - - // specifics - // NOTE: this is ONLY for use where a sql query is 1 time use, otherwise add as argument - // ... for later use, (above) - // PLEASE do not use the or switch without discussing case with WH - 'additionalWhereArr' => false, - 'additional_joins' => false, - 'whereCase' => 'AND' // DEFAULT = AND - - - - ); 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 = ''; - - $join_sql = ''; - - #} ============= PRE-QUERY ============ - - #} Capitalise this - $sortOrder = strtoupper($sortOrder); - if ( ! in_array( $sortOrder, array( 'ASC', 'DESC' ) ) ) { - $sortOrder = 'ASC'; - } - - // If just count or simplified, turn off any extras - if ( $count || $simplified || $onlyObjTotals ) { - $withCustomFields = false; - $withQuotes = false; - $withInvoices = false; - $withTransactions = false; - $withTasks = false; - $withLogs = false; - $withLastLog = false; - $withTags = false; - $withOwner = false; - $withAssigned = false; - $withDND = false; - $withAliases = 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; - $withQuotes = false; - $withInvoices = false; - $withTransactions = false; - $withTasks = false; - $withLogs = false; - $withLastLog = false; - $withTags = false; - $withOwner = false; - $withAssigned = false; - $withDND = false; - $withAliases = false; - $withExternalSources = false; - $withExternalSourcesGrouped = 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_CONTACT)); - - #} 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); - - // 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 ); - - } - - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ".$cKey; - - // add params - $params[] = $cK; $params[] = ZBS_TYPE_CONTACT; - - } - - } - - #} Aliases - // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. - if ($withAliases){ + #} Aliases + if ( $withAliases ) { #} Retrieve these as a CSV :) $extraSelect .= ',(SELECT ' . $this->DAL()->build_group_concat( 'aka_alias', ',' ) . ' FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_id = contact.ID) aliases'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } - - // Add any addr custom fields for addr1+addr2 - // no need if simpliefied or count parameters passed - if ( !$simplified && !$count && !$onlyColumns && !$onlyObjTotals ){ - $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 (contacts need the prefix 'zbsc_' :rolls-eyes:) - if ('zbsc_'.$cfKey == $sortByField) $sortByField = $cKey; - if ('zbsc_'.$cfKey2 == $sortByField) $sortByField = $cKey2; - - // addr 1 - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey; - // add params - $params[] = $cfKey; $params[] = ZBS_TYPE_CONTACT; - // addr 2 - // add as subquery - $extraSelect .= ',(SELECT zbscf_objval FROM '.$ZBSCRM_t['customfields']." WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ".$cKey2; - // add params - $params[] = $cfKey2; $params[] = ZBS_TYPE_CONTACT; - - } - - - } - - } - - - // ==== TOTAL VALUES + } - // If we're sorting by total value, we need the values - if ( $sortByField === 'totalvalue' ) { - $withValues = true; - } + // 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 ); + + // addr 1 + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey; + // add params + $params[] = $cfKey; + $params[] = ZBS_TYPE_CONTACT; + // addr 2 + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey2; + // add params + $params[] = $cfKey2; + $params[] = ZBS_TYPE_CONTACT; - // 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 :) + // ==== TOTAL VALUES - // only include transactions with statuses which should be included in total value: - $transStatusQueryAdd = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); + // Calculate total vals etc. with SQL + if ( $withValues && ! $onlyID ) { + // only include transactions with statuses which should be included in total value: + $transStatusQueryAdd = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase // 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_CONTACT." AND zbsol_objid_to = contact.ID)) as quotes_total"; - // invs: + // 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_CONTACT . ' AND zbsol_objid_to = contact.ID)) as quotes_total'; + // invs not including deleted: $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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.ID)) as invoices_total_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -1304,3948 +706,5024 @@ public function getContacts($args=array()){ $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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT." AND zbsol_objid_to = contact.ID)".$transStatusQueryAdd.") as transactions_total"; - // paid balance against invs (also in getContact) - // (this allows us to subtract from totals to get a true figure where transactions are part/whole payments for invs) - /* + $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_CONTACT . ' AND zbsol_objid_to = contact.ID)' . $transStatusQueryAdd . ') as transactions_total'; + // paid balance against invs (also in getContacts) + // (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: - 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 * 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 = 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 + 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_CONTACT . ' AND zbsol_objid_to = contact.ID)'; + $extraSelect .= ')' . $transStatusQueryAdd . ') as transactions_paid_total'; + } - */ - $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_CONTACT.' AND zbsol_objid_to = contact.ID)'; - $extraSelect .= ')'.$transStatusQueryAdd.') as transactions_paid_total'; + // ==== / TOTAL VALUES - } + $selector = 'contact.*'; + if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $selector = ''; - // ==== / TOTAL VALUES + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'contact.ID'; + } - // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. - if ($withDND){ + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'contact.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'contact.ID'; + } - // add as subquery - $extraSelect .= ',(SELECT zbsm_val FROM '.$ZBSCRM_t['meta']." WHERE zbsm_objid = contact.ID AND zbsm_key = %s AND zbsm_objtype = ".ZBS_TYPE_CONTACT." LIMIT 1) dnd"; - - // add params - $params[] = 'do-not-email'; + #} ============ / PRE-QUERY =========== - } + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['contacts'] . ' as contact'; + #} ============= WHERE ================ - #} ============ / PRE-QUERY =========== + if ( ! empty( $id ) && $id > 0 ) { + + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - if ( ! empty( $additional_joins ) ) { - list( $join_sql, $join_params ) = $this->DAL()->build_joins( $additional_joins, $whereCase === 'AND' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable } - #} Build query - $query = "SELECT contact.*".$extraSelect." FROM ".$ZBSCRM_t['contacts'].' as contact'.$joinQ; - - #} Count override - if ($count) $query = "SELECT COUNT(contact.ID) FROM ".$ZBSCRM_t['contacts'].' as contact'.$joinQ; - - #} simplified override - if ($simplified) $query = "SELECT contact.ID as id,CONCAT(contact.zbsc_fname,\" \",contact.zbsc_lname) as name,contact.zbsc_created as created, contact.zbsc_email as email FROM ".$ZBSCRM_t['contacts'].' as contact'.$joinQ; - - #} onlyColumns override - if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ - - $columnStr = ''; - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ - - if (!empty($columnStr)) $columnStr .= ','; - // this presumes str is db-safe? could do with sanitation? - $columnStr .= $colDBKey; - - } + if ( ! empty( $email ) ) { - $query = "SELECT ".$columnStr." FROM ".$ZBSCRM_t['contacts'].' as contact'.$joinQ; + // where we're seeking the ID from an email we can override the query for performance benefits (#gh-2450): + if ( $onlyID ) { - } + $query = 'SELECT contact.ID FROM ( SELECT contact.ID FROM ' . $ZBSCRM_t['contacts'] . ' as contact WHERE zbsc_email = %s UNION ALL SELECT aka_id AS ID FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = 1 AND aka_alias = %s) contact'; + $wheres = array( 'direct' => array() ); + $params = array( $email, $email ); + } else { - #} ============= WHERE ================ - - #} Add Search phrase - if (!empty($searchPhrase)){ - - // inefficient searching all fields. Maybe get settings from user "which fields to search" - // ... and auto compile for each contact ahead of time - $searchWheres = array(); - $searchWheres['search_fullname'] = array('CONCAT(zbsc_prefix, " ", zbsc_fname, " ", zbsc_lname)','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_fname'] = array('zbsc_fname','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_lname'] = array('zbsc_lname','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_email'] = array('zbsc_email','LIKE','%s','%'.$searchPhrase.'%'); + $emailWheres = array(); - // address elements - $searchWheres['search_addr1'] = array('zbsc_addr1','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_addr2'] = array('zbsc_addr2','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_city'] = array('zbsc_city','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_county'] = array('zbsc_county','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_country'] = array('zbsc_country','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_postcode'] = array('zbsc_postcode','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_secaddr1'] = array('zbsc_secaddr1','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_secaddr2'] = array('zbsc_secaddr2','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_seccity'] = array('zbsc_seccity','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_seccounty'] = array('zbsc_seccounty','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_seccountry'] = array('zbsc_seccountry','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_secpostcode'] = array('zbsc_secpostcode','LIKE','%s','%'.$searchPhrase.'%'); + #} Add ID + $emailWheres['emailcheck'] = array( 'zbsc_email', '=', '%s', $email ); - // social - $searchWheres['search_tw'] = array('zbsc_tw','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_li'] = array('zbsc_li','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_fb'] = array('zbsc_fb','LIKE','%s','%'.$searchPhrase.'%'); + #} Check AKA + $emailWheres['email_alias'] = array( 'ID', 'IN', '(SELECT aka_id FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_alias = %s)', $email ); - // phones - // ultimately when search is refactored, we should probably store the "clean" version of the phone numbers in the database - $searchWheres['search_hometel'] = array('REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(zbsc_hometel," ",""),".",""),"-",""),"(",""),")","")','LIKE','%s','%'.(str_replace(array(' ','.','-','(',')'),'',$searchPhrase)).'%'); - $searchWheres['search_worktel'] = array('REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(zbsc_worktel," ",""),".",""),"-",""),"(",""),")","")','LIKE','%s','%'.(str_replace(array(' ','.','-','(',')'),'',$searchPhrase)).'%'); - $searchWheres['search_mobtel'] = array('REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(zbsc_mobtel," ",""),".",""),"-",""),"(",""),")","")','LIKE','%s','%'.(str_replace(array(' ','.','-','(',')'),'',$searchPhrase)).'%'); + // 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 ); - // We also add this, which finds AKA emails if using email - $searchWheres['search_alias'] = array('ID','IN',"(SELECT aka_id FROM ".$ZBSCRM_t['aka']." WHERE aka_type = ".ZBS_TYPE_CONTACT." AND aka_alias = %s)",$searchPhrase); + if ( is_array( $emailSearchQueryArr ) && isset( $emailSearchQueryArr['where'] ) && ! empty( $emailSearchQueryArr['where'] ) ) { - // 2.99.9.11 - Added ability to search custom fields (optionally) - $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); - if ($customFieldSearch == 1){ + // add it + $wheres['direct'][] = array( '(' . $emailSearchQueryArr['where'] . ')', $emailSearchQueryArr['params'] ); - // simplistic add - // NOTE: This IGNORES ownership of custom field lines. - // use FULLTEXT index if available (MySQL 5.6+), otherwise use fallback - if ( jpcrm_migration_table_has_index( $ZBSCRM_t['customfields'], 'search' ) ) { - $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE MATCH(zbscf_objval) AGAINST(%s) AND zbscf_objtype = ".ZBS_TYPE_CONTACT.")",$searchPhrase); - } else { - $searchWheres['search_customfields'] = array('ID','IN',"(SELECT zbscf_objid FROM ".$ZBSCRM_t['customfields']." WHERE zbscf_objval LIKE %s AND zbscf_objtype = ".ZBS_TYPE_CONTACT.")",'%'.$searchPhrase.'%'); - } + } + } + } - } - - // also search "company name" where assigned - $b2bMode = zeroBSCRM_getSetting('companylevelcustomers'); - // OWNERSHIP TODO - next query doesn't USE OWNERSHIP!!!!: - if ($b2bMode == 1) $searchWheres['incompanywithname'] = array('ID','IN','(SELECT DISTINCT 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 IN (SELECT ID FROM ".$ZBSCRM_t['companies']." WHERE zbsco_name LIKE %s))",'%'.$searchPhrase.'%'); + if ( ! empty( $WPID ) && $WPID > 0 ) { - // This generates a query like 'zbsc_fname LIKE %s OR zbsc_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['WPID'] = array( 'zbsc_wpid', '=', '%d', $WPID ); - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + } - } + if ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) { - } + $wheres['extsourcecheck'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_CONTACT . ' AND zbss_source = %s AND zbss_uid = %s)', array( $externalSource, $externalSourceUID ) ); - #} In company? #DB1LEGACY (TOMOVE -> where) - if (!empty($inCompany) && $inCompany > 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['incompany'] = array('ID','IN','(SELECT DISTINCT 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 = %d)",$inCompany); - - } - - #} 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); - - } - - // 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_CONTACT." AND zbss_source = %s)",$externalSource); - - } - - // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed - - // quick addition for mike - #} olderThan - if ( ! empty( $olderThan ) && $olderThan > 0 ) $wheres['olderThan'] = array( 'zbsc_created', '<=', '%d', $olderThan ); - #} newerThan - if ( ! empty( $newerThan ) && $newerThan > 0 ) $wheres['newerThan'] = array( 'zbsc_created', '>=', '%d', $newerThan ); - - // status - if ( ! empty( $hasStatus ) ) $wheres['hasStatus'] = array( 'zbsc_status', '=', '%s', $hasStatus ); - if ( ! empty( $otherStatus ) ) $wheres['otherStatus'] = array( 'zbsc_status', '<>', '%s', $otherStatus ); - - #} contactedBefore - if ( ! empty( $contactedBefore ) && $contactedBefore > 0 ) $wheres['contactedBefore'] = array( 'zbsc_lastcontacted', '<=', '%d', $contactedBefore ); - #} contactedAfter - if ( ! empty( $contactedAfter ) && $contactedAfter > 0 ) $wheres['contactedAfter'] = array( 'zbsc_lastcontacted', '>=', '%d', $contactedAfter ); - - #} hasEmail - if ( ! empty( $hasEmail ) ) { - $wheres['hasEmail'] = array( 'zbsc_email', '=', '%s', $hasEmail ); - $wheres['hasEmailAlias'] = array( 'ID', 'IN', '(SELECT aka_id FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_alias = %s)', $hasEmail ); } - #} inCounty - if ( ! empty( $inCounty ) ) { - $wheres['inCounty'] = array( 'zbsc_county', '=', '%s', $inCounty ); - $wheres['inCountyAddr2'] = array( 'zbsc_secaddrcounty', '=', '%s', $inCounty ); - } - #} inPostCode - if ( ! empty( $inPostCode ) ) { - $wheres['inPostCode'] = array( 'zbsc_postcode', '=', '%s', $inPostCode ); - $wheres['inPostCodeAddr2'] = array( 'zbsc_secaddrpostcode', '=', '%s', $inPostCode ); - } - #} inCountry - if ( ! empty( $inCountry ) ) { - $wheres['inCountry'] = array( 'zbsc_country', '=', '%s', $inCountry ); - $wheres['inCountryAddr2'] = array( 'zbsc_secaddrcountry', '=', '%s', $inCountry ); - } - #} notInCounty - if ( ! empty( $notInCounty ) ) { - $wheres['notInCounty'] = array( 'zbsc_county', '<>', '%s', $notInCounty ); - $wheres['notInCountyAddr2'] = array( 'zbsc_secaddrcounty', '<>', '%s', $notInCounty ); - } - #} notInPostCode - if ( ! empty( $notInPostCode ) ) { - $wheres['notInPostCode'] = array( 'zbsc_postcode', '<>', '%s', $notInPostCode ); - $wheres['notInPostCodeAddr2'] = array( 'zbsc_secaddrpostcode', '<>', '%s', $notInPostCode ); - } - #} notInCountry - if ( ! empty( $notInCountry ) ) { - $wheres['notInCountry'] = array( 'zbsc_country', '<>', '%s', $notInCountry ); - $wheres['notInCountryAddr2'] = array( 'zbsc_secaddrcountry', '<>', '%s', $notInCountry ); - } + #} ============ / WHERE ============== - // generic obj links, e.g. quotes, invs, trans - // e.g. contact(s) assigned to inv 123 - // Where the link relationship is OBJECT -> CONTACT - if ( ! empty( $hasObjIDLinkedTo ) && $hasObjIDLinkedTo > 0 && - ! empty( $hasObjTypeLinkedTo ) && $hasObjTypeLinkedTo > 0 ) { - $wheres['hasObjIDLinkedTo'] = array( 'ID', 'IN', '(SELECT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = %d AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_from = %d AND zbsol_objid_to = contact.ID)', array( $hasObjTypeLinkedTo, $hasObjIDLinkedTo ) ); + #} 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 - // generic obj links, e.g. companies - // Where the link relationship is CONTACT -> OBJECT - if ( ! empty( $isLinkedToObjID ) && $isLinkedToObjID > 0 && - ! empty( $isLinkedToObjType ) && $isLinkedToObjType > 0 ) { - $wheres['isLinkedToObjID'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objtype_to = %d AND zbsol_objid_from = contact.ID AND zbsol_objid_to = %d)', array( $isLinkedToObjType, $isLinkedToObjID ) ); - } - // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - // Any additionalWhereArr? - if ( is_array( $additionalWhereArr ) && count( $additionalWhereArr ) > 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + try { - // add em onto wheres (note these will OVERRIDE if using a key used above) - // Needs to be multi-dimensional $wheres = array_merge($wheres,$additionalWhereArr); - $wheres = array_merge_recursive($wheres,$additionalWhereArr); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - } + } catch ( Exception $e ) { + #} General SQL Err + $this->catchSQLError( $e ); - #} Quick filters - adapted from DAL1 (probs can be slicker) - if (is_array($quickFilters) && count($quickFilters) > 0){ + } - // cycle through - foreach ($quickFilters as $qFilter){ + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - // where status = x - // USE hasStatus above now... - if ( str_starts_with( $qFilter, 'status_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + #} Has results, tidy + return - $quick_filter_status = substr( $qFilter, 7 ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $wheres['quickfilterstatus'] = array( 'zbsc_status', '=', 'convert(%s using utf8mb4) collate utf8mb4_bin', $quick_filter_status ); + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } - } elseif ( $qFilter === 'assigned_to_me' ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $wheres['assigned_to_me'] = array( 'zbs_owner', '=', zeroBSCRM_user() ); + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_contact( $potentialRes, $withCustomFields ); + } - } elseif ( $qFilter === 'not_assigned' ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $wheres['not_assigned'] = array( 'zbs_owner', '<=', '0' ); + if ( $withTags ) { - } elseif ( str_starts_with( $qFilter, 'notcontactedin' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_CONTACT, + 'objid' => $potentialRes->ID, + ) + ); - // check - $notcontactedinDays = (int)substr($qFilter,14); - $notcontactedinDaysSeconds = $notcontactedinDays*86400; - $wheres['notcontactedinx'] = array('zbsc_lastcontacted','<','%d',time()-$notcontactedinDaysSeconds); + } - } elseif ( str_starts_with( $qFilter, 'olderthan' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // =================================================== + // ========== #} #DB1LEGACY (TOMOVE) + // == Following is all using OLD DB stuff, here until we migrate inv etc. + // =================================================== - // check - $olderThanDays = (int)substr($qFilter,9); - $olderThanDaysSeconds = $olderThanDays*86400; - $wheres['olderthanx'] = array('zbsc_created','<','%d',time()-$olderThanDaysSeconds); + #} With most recent log? #DB1LEGACY (TOMOVE) + if ( $withLastLog ) { - } elseif ( str_starts_with( $qFilter, 'segment_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $res['lastlog'] = $this->DAL()->logs->getLogsForObj( + array( - // a SEGMENT - $qFilterSegmentSlug = substr($qFilter,8); + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $potentialRes->ID, - #} Retrieve segment + conditions - $segment = $this->DAL()->segments->getSegmentBySlug($qFilterSegmentSlug,true,false); - $conditions = array(); if (isset($segment['conditions'])) $conditions = $segment['conditions']; - $matchType = 'all'; if (isset($segment['matchtype'])) $matchType = $segment['matchtype']; + 'incMeta' => true, - // retrieve getContacts arguments from a list of segment conditions - // as at launch of segments (26/6/18) - these are all $additionalWhere args - // ... if it stays that way, this is nice and simple, so going to proceed with that. - // be aware if $this->segmentConditionArgs() changes, will affect this. - $contactGetArgs = $this->DAL()->segments->segmentConditionsToArgs($conditions,$matchType); + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, - // as at above, contactGetArgs should have this: - if (isset($contactGetArgs['additionalWhereArr']) && is_array($contactGetArgs['additionalWhereArr'])){ + ) + ); - // This was required to work with OR and AND situs, along with the usual getContacts vars as well - // ----------------------- - // match type ALL is default, this switches to ANY - $segmentOperator = 'AND'; if ($matchType == 'one') $segmentOperator = 'OR'; + } - // This generates a query like 'zbsc_fname LIKE %s OR/AND zbsc_lname LIKE %s', - // which we then need to include as direct subquery (below) in main query :) - $segmentQueryArr = $this->buildWheres($contactGetArgs['additionalWhereArr'],'',array(),$segmentOperator,false); - - if (is_array($segmentQueryArr) && isset($segmentQueryArr['where']) && !empty($segmentQueryArr['where'])){ + #} With Assigned? + if ( $withOwner ) { - // add it - $wheres['direct'][] = array('('.$segmentQueryArr['where'].')',$segmentQueryArr['params']); + $res['owner'] = zeroBS_getOwner( $potentialRes->ID, true, 'zerobs_customer', $potentialRes->zbs_owner ); - } - // ----------------------- + } + // Objects: return all, unless $with_obj_limit + $objs_page = -1; + $objs_per_page = -1; + $with_obj_limit = (int) $with_obj_limit; + if ( $with_obj_limit > 0 ) { - // following didn't work for OR situations: (worked for most situations though, is a shame) - // ----------------------- - // so we MERGE that into our wheres... :o - // this'll override any settings above. - // Needs to be multi-dimensional - //$wheres = array_merge_recursive($wheres,$contactGetArgs['additionalWhereArr']); - // ----------------------- + $objs_page = 0; + $objs_per_page = $with_obj_limit; - } elseif ( ! empty( $contactGetArgs['additional_joins'] ) && is_array( $contactGetArgs['additional_joins'] ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, + } - list( $join_sql, $join_params ) = $this->DAL()->build_joins( $contactGetArgs['additional_joins'], $matchType === 'all' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } - } else { + if ( $withInvoices ) { - // normal/hardtyped + #} only gets first 100? + // DAL3 ver, more perf, gets all + $res['invoices'] = $zbs->DAL->invoices->getInvoices( + array( - switch ($qFilter){ + 'assignedContact' => $potentialRes->ID, // assigned to company id (int) + 'page' => $objs_page, + 'perPage' => $objs_per_page, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', + 'withAssigned' => false, // no need, it's assigned to this obj already + ) + ); - case 'lead': + } - // hack "leads only" - adapted from DAL1 (probs can be slicker) - $wheres['quickfilterlead'] = array('zbsc_status','LIKE','%s','Lead'); + if ( $withQuotes ) { - break; + // DAL3 ver, more perf, gets all + $res['quotes'] = $zbs->DAL->quotes->getQuotes( + array( + 'assignedContact' => $potentialRes->ID, // assigned to company id (int) + 'page' => $objs_page, + 'perPage' => $objs_per_page, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', + 'withAssigned' => false, // no need, it's assigned to this obj already - case 'customer': + ) + ); - // hack - adapted from DAL1 (probs can be slicker) - $wheres['quickfiltercustomer'] = array( 'zbsc_status', 'LIKE', '%s', 'Customer' ); + } - break; + #} ... brutal for mvp #DB1LEGACY (TOMOVE) + if ( $withTransactions ) { - default: + // DAL3 ver, more perf, gets all + $res['transactions'] = $zbs->DAL->transactions->getTransactions( + array( - // if we've hit no filter query, let external logic hook in to provide alternatives - // First used in WooSync module - $wheres = apply_filters( 'jpcrm_contact_query_quickfilter', $wheres, $qFilter ); + 'assignedContact' => $potentialRes->ID, // assigned to company id (int) + 'page' => $objs_page, + 'perPage' => $objs_per_page, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', + 'withAssigned' => false, // no need, it's assigned to this obj already - break; + ) + ); - } // / switch + } + // } + #} With co's? + if ( $withCompanies ) { - } // / hardtyped + // add all company lines + $res['companies'] = $this->DAL()->getObjsLinkedToObj( + array( + 'objtypefrom' => ZBS_TYPE_CONTACT, // contact + 'objtypeto' => ZBS_TYPE_COMPANY, // company + 'objfromid' => $potentialRes->ID, + ) + ); - } + } - } // / quickfilters + #} ... brutal for mvp #DB1LEGACY (TOMOVE) + if ( $withTasks ) { - #} Is Tagged (expects 1 tag ID OR array) + // DAL3 ver, more perf, gets all + $res['tasks'] = $zbs->DAL->events->getEvents( + array( - // catch 1 item arr - if (is_array($isTagged) && count($isTagged) == 1) $isTagged = $isTagged[0]; + 'assignedContact' => $potentialRes->ID, // assigned to company id (int) + 'page' => $objs_page, + 'perPage' => $objs_per_page, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TASK ), + 'sortByField' => 'zbse_start', + 'sortOrder' => 'DESC', + 'withAssigned' => false, // no need, it's assigned to this obj already - 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 = contact.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_CONTACT,$isTagged)); + } - } else if (is_array($isTagged) && count($isTagged) > 0){ + // simplistic, could be optimised (though low use means later.) + if ( $withExternalSources ) { - // foreach in array :) - $tagStr = ''; - foreach ($isTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + $res['external_sources'] = $zbs->DAL->contacts->getExternalSourcesForContact( + array( - 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 = contact.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_CONTACT,$tagStr)); + 'contactID' => $potentialRes->ID, - } + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - } - #} Is NOT Tagged (expects 1 tag ID OR array) + ) + ); - // catch 1 item arr - if (is_array($isNotTagged) && count($isNotTagged) == 1) $isNotTagged = $isNotTagged[0]; + } + if ( $withExternalSourcesGrouped ) { - if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $res['external_sources'] = $zbs->DAL->getExternalSources( + -1, + array( - // add where tagged - // 1 int: - $wheres['direct'][] = 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,$isNotTagged)); + 'objectID' => $potentialRes->ID, + 'objectType' => ZBS_TYPE_CONTACT, + 'grouped_by_source' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - } 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 = contact.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_CONTACT,$tagStr)); + // =================================================== + // ========== / #DB1LEGACY (TOMOVE) + // =================================================== - } + return $res; - } + } + } // / if ID + + return false; + } + + // TODO $argsOverride=false + /** + * returns contact detail lines + * + * @param array $args Associative array of arguments + * withQuotes, withInvoices, withTransactions, withLogs, searchPhrase, sortByField, sortOrder, page, perPage + * + * @return array of contact lines + */ + public function getContacts( $args = array() ) { + + global $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'searchPhrase' => '', // searches which fields? + 'inCompany' => false, // will be an ID if used + 'inArr' => false, + 'quickFilters' => 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' + + // last contacted + 'contactedBefore' => false, // uts + 'contactedAfter' => false, // uts + + // email + 'hasEmail' => false, // 'x@y.com' either in main field or as AKA + + // 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, + 'onlyObjTotals' => false, // if passed, returns for group: 'total' 'invoices_total' 'transactions_total' etc. (requires getting a lot of objs, use sparingly) + 'withCustomFields' => true, + 'withQuotes' => false, + 'withInvoices' => false, + 'withTransactions' => false, + 'withTasks' => false, + 'withLogs' => false, + 'withLastLog' => false, + 'withTags' => false, + 'withOwner' => false, + 'withAssigned' => false, // return ['company'] objs if has link + 'withDND' => false, // if true, returns getContactDoNotMail as well :) + 'simplified' => false, // returns just id,name,created,email (for typeaheads) + 'withValues' => false, // if passed, returns with 'total' 'invoices_total' 'transactions_total' etc. (requires getting all obj, use sparingly) + '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) + 'withAliases' => false, + 'withExternalSources' => false, + 'withExternalSourcesGrouped' => false, + + '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_CONTACT ), // this'll let you not-check the owner of obj + + // 'argsOverride' => ?? Still req? + + // specifics + // NOTE: this is ONLY for use where a sql query is 1 time use, otherwise add as argument + // ... for later use, (above) + // PLEASE do not use the or switch without discussing case with WH + 'additionalWhereArr' => false, + 'additional_joins' => false, + 'whereCase' => 'AND', // DEFAULT = AND + + ); + 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 =============== + global $ZBSCRM_t, $wpdb, $zbs; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); + $joinQ = ''; + $extraSelect = ''; - #} ============ SORT ============== + $join_sql = ''; - // latest log - // Latest Contact Log (as sort) needs an additional SQL where str: - $contact_log_types_str = ''; - $sort_function = 'MAX'; - if ( $sortOrder !== 'DESC' ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $sort_function = 'MIN'; - } - // @phan-suppress-next-line PhanImpossibleCondition -- This var is initialized by arbitrary data in $args. - if ( $withLastLog ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + #} ============= PRE-QUERY ============ - // retrieve log types to include - $contact_log_types = $zbs->DAL->logs->contact_log_types; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); + if ( ! in_array( $sortOrder, array( 'ASC', 'DESC' ) ) ) { + $sortOrder = 'ASC'; + } - // build sql - if ( is_array( $contact_log_types ) ) { - // create escaped csv - $contact_log_types_str = $this->build_csv( $contact_log_types ); - } - } + // If just count or simplified, turn off any extras + if ( $count || $simplified || $onlyObjTotals ) { + $withCustomFields = false; + $withQuotes = false; + $withInvoices = false; + $withTransactions = false; + $withTasks = false; + $withLogs = false; + $withLastLog = false; + $withTags = false; + $withOwner = false; + $withAssigned = false; + $withDND = false; + $withAliases = false; + $withExternalSources = false; + $withExternalSourcesGrouped = false; + } - // 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(); + #} If onlyColumns, validate + if ( $onlyColumns ) { - // Mapped sorts - // This catches listview and other specific sort cases - // Note: Prefix here is a legacy leftover from the fact the AJAX List view retrieve goes through zeroBS_getCustomers() which prefixes zbsc_ - $sort_map = array( - 'zbsc_id' => 'ID', - 'zbsc_owner' => 'zbs_owner', - 'zbsc_zbs_owner' => 'zbs_owner', - - // company (name) - 'zbsc_company' => '(SELECT zbsco_name FROM ' . $ZBSCRM_t['companies'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_from = contact.ID) ORDER BY zbsco_name ' . $sortOrder . ' LIMIT 0,1)', // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - // sort by subquery: Logs - // sort by latest log is effectively 'sort by last log added' - 'zbsc_latestlog' => '(SELECT ' . $sort_function . '(zbsl_created) FROM ' . $ZBSCRM_t['logs'] . ' WHERE zbsl_objid = contact.ID AND zbsl_objtype = ' . ZBS_TYPE_CONTACT . ')', // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // sort by latest contact log is effectively 'sort by last contact log added' (requires $withLastLog = true) - 'zbsc_lastcontacted' => '(SELECT ' . $sort_function . '(zbsl_created) FROM ' . $ZBSCRM_t['logs'] . ' WHERE zbsl_objid = contact.ID AND zbsl_objtype = ' . ZBS_TYPE_CONTACT . ' AND zbsl_type IN (' . $contact_log_types_str . '))', // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - // has & counts (same queries) - // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', - 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', - 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', - 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', - 'zbsc_invoicecount_inc_deleted' => '(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_CONTACT . ' AND zbsol_objid_to = contact.ID))', - 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID)' . $inv_status_query_add . ')', - 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', - // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // following will only work if obj total value subqueries triggered above ^ - 'zbsc_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) - 'zbsc_transactiontotal' => 'transactions_total', - 'zbsc_quotetotal' => 'quotes_total', - 'zbsc_invoicetotal' => 'invoices_total', - ); - - // either from $sort_map, or multi-dimensional name search - if ( array_key_exists( $sortByField, $sort_map ) ) { + #} 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']; + } - $sortByField = $sort_map[ $sortByField ]; + if ( ! empty( $dbCol ) ) { - } - elseif ( $sortByField === 'zbsc_fullname' || $sortByField === 'fullname' ) { - - $sortByField = array( 'zbsc_lname' => $sortOrder, 'zbsc_fname' => $sortOrder ); + $onlyColumnsFieldArr[ $dbCol ] = $col; - } + } + } + } + // if legit cols: + if ( isset( $onlyColumnsFieldArr ) && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - #} ============ / SORT ============== + $onlyColumns = true; - #} CHECK this + reset to default if faulty - if (!in_array($whereCase,array('AND','OR'))) $whereCase = 'AND'; + // If onlyColumns, turn off extras + $withCustomFields = false; + $withQuotes = false; + $withInvoices = false; + $withTransactions = false; + $withTasks = false; + $withLogs = false; + $withLastLog = false; + $withTags = false; + $withOwner = false; + $withAssigned = false; + $withDND = false; + $withAliases = false; + $withExternalSources = false; + $withExternalSourcesGrouped = false; - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params,$whereCase); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + } else { - #} 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 + // deny + $onlyColumns = false; - $query .= $join_sql; + } + } - if ( ! empty( $join_sql ) ) { - $params = array_merge( $params, $join_params ); - } + #} Custom Fields + // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. + if ( $withCustomFields ) { - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_CONTACT ) ); - try { + #} Cycle through + build into query + if ( is_array( $custFields ) ) { + foreach ( $custFields as $cK => $cF ) { - // Prep & run query - $queryObj = $this->prepare($query,$params); + // 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 ) { - // Catch count + return if requested - if ( $count ) return $wpdb->get_var( $queryObj ); + // sort by + $sortByField = $cKey; - // Totals override - // This is non-performant, and shouldn't run when we've got extra joins (e.g. from segments). - if ( $onlyObjTotals && empty( $join_sql ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + // check if sort needs any CAST (e.g. numeric): + $sortByField = $this->DAL()->build_custom_field_order_by_str( $sortByField, $cF ); - $contact_query = 'SELECT contact.ID FROM ' . $ZBSCRM_t['contacts'] . ' AS contact' . $joinQ . $this->buildWhereStr( $whereStr, $additionalWhere ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $contact_query = $this->prepare($contact_query,$params); + } - $query = "SELECT "; + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ' . $cKey; - if ( zeroBSCRM_getSetting( 'feat_quotes' ) == 1 ){ + // add params + $params[] = $cK; + $params[] = ZBS_TYPE_CONTACT; - $query .= "(SELECT SUM(q.zbsq_value) - FROM " . $ZBSCRM_t['quotes'] . " AS q - INNER JOIN " . $ZBSCRM_t['objlinks'] . " AS ol - ON q.ID = ol.zbsol_objid_from - WHERE - ol.zbsol_objtype_from = " . ZBS_TYPE_QUOTE . " - AND ol.zbsol_objtype_to = " . ZBS_TYPE_CONTACT . " - AND ol.zbsol_objid_to IN ( " . $contact_query . " )) AS quotes_total"; + } + } + } - } + #} Aliases + // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. + if ( $withAliases ) { - if ( zeroBSCRM_getSetting( 'feat_invs' ) == 1 ){ + #} Retrieve these as a CSV :) + $extraSelect .= ',(SELECT ' . $this->DAL()->build_group_concat( 'aka_alias', ',' ) . ' FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_id = contact.ID) aliases'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // if previous query, add comma - if ( $query !== "SELECT " ){ - $query .= ", "; - } + } - // 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(); + // Add any addr custom fields for addr1+addr2 + // no need if simpliefied or count parameters passed + if ( ! $simplified && ! $count && ! $onlyColumns && ! $onlyObjTotals ) { + $addrCustomFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); + if ( is_array( $addrCustomFields ) && count( $addrCustomFields ) > 0 ) { - // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $query .= '(SELECT SUM(i.zbsi_total) - FROM ' . $ZBSCRM_t['invoices'] . ' AS i - INNER JOIN ' . $ZBSCRM_t['objlinks'] . ' AS ol - ON i.ID = ol.zbsol_objid_from - WHERE - ol.zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' - AND ol.zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' - AND ol.zbsol_objid_to IN ( ' . $contact_query . ' ) ' . $inv_status_query_add . ') AS invoices_total,'; + foreach ( $addrCustomFields as $cK => $cF ) { - $query .= '(SELECT SUM(inc_deleted_invoices.zbsi_total) - FROM ' . $ZBSCRM_t['invoices'] . ' AS inc_deleted_invoices - INNER JOIN ' . $ZBSCRM_t['objlinks'] . ' AS ol - ON inc_deleted_invoices.ID = ol.zbsol_objid_from - WHERE - ol.zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' - AND ol.zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' - AND ol.zbsol_objid_to IN ( ' . $contact_query . ' )) AS invoices_total_inc_deleted'; - // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + // custom field key + $cfKey = 'addr_' . $cK; + $cfKey2 = 'secaddr_' . $cK; - if ( zeroBSCRM_getSetting( 'feat_transactions' ) == 1 ){ + // 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 previous query, add comma - if ( $query !== "SELECT " ){ - $query .= ", "; - } + // we also check the $sortByField in case that's the same cf (contacts need the prefix 'zbsc_' :rolls-eyes:) + if ( 'zbsc_' . $cfKey == $sortByField ) { + $sortByField = $cKey; + } + if ( 'zbsc_' . $cfKey2 == $sortByField ) { + $sortByField = $cKey2; + } - // only include transactions with statuses which should be included in total value: - $transaction_status_query_addition = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); + // addr 1 + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey; + // add params + $params[] = $cfKey; + $params[] = ZBS_TYPE_CONTACT; + // addr 2 + // add as subquery + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = contact.ID AND zbscf_objkey = %s AND zbscf_objtype = %d) ' . $cKey2; + // add params + $params[] = $cfKey2; + $params[] = ZBS_TYPE_CONTACT; - $query .= "(SELECT SUM(t.zbst_total) - FROM " . $ZBSCRM_t['transactions'] . " AS t - INNER JOIN " . $ZBSCRM_t['objlinks'] . " AS ol - ON t.ID = ol.zbsol_objid_from - WHERE - ol.zbsol_objtype_from = " . ZBS_TYPE_TRANSACTION . " - AND ol.zbsol_objtype_to = " . ZBS_TYPE_CONTACT . " - AND ol.zbsol_objid_to IN ( " . $contact_query . " ) " . $transaction_status_query_addition . ") AS transactions_total, "; + } + } + } - $query .= "(SELECT SUM(assigned_transactions.zbst_total) - FROM " . $ZBSCRM_t['transactions'] . " AS assigned_transactions - WHERE assigned_transactions.ID IN - ( - 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 - ( - SELECT DISTINCT zbsol_objid_from - FROM " . $ZBSCRM_t['objlinks'] . " - WHERE zbsol_objtype_from = " . ZBS_TYPE_INVOICE . " AND - zbsol_objtype_to = " . ZBS_TYPE_CONTACT . " AND - zbsol_objid_to IN ( " . $contact_query . " ) - ) - )) AS assigned_transactions_total"; + // ==== TOTAL VALUES - } + // If we're sorting by total value, we need the values + if ( $sortByField === 'totalvalue' ) { + $withValues = true; + } - if ( $query !== "SELECT " ){ + // Calculate total vals etc. with SQL + if ( ! $simplified && ! $count && $withValues && ! $onlyColumns ) { - $totals_data = $wpdb->get_row( $query ); + // 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(); - if ( zeroBSCRM_getSetting( 'feat_invs' ) == 1 && zeroBSCRM_getSetting( 'feat_transactions' ) == 1 ){ + // 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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.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_CONTACT . ' AND zbsol_objid_to = contact.ID)) as invoices_count_inc_deleted'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // calculate a total sum (invoices + unassigned transactions) - $totals_data->total_sum = (float)$totals_data->invoices_total + (float)$totals_data->transactions_total - (float)$totals_data->assigned_transactions_total; - //total_sum_inc_deleted currently factors in deleted invoices - $totals_data->total_sum_inc_deleted = (float) $totals_data->invoices_total_inc_deleted + (float) $totals_data->transactions_total - (float) $totals_data->assigned_transactions_total; + // 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_CONTACT . ' AND zbsol_objid_to = contact.ID)' . $transStatusQueryAdd . ') as transactions_total'; + // paid balance against invs (also in getContact) + // (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: - } elseif ( zeroBSCRM_getSetting( 'feat_invs' ) == 1 ){ + ========== - // just include invoices in total - $totals_data->total_sum = (float) $totals_data->invoices_total; - $totals_data->total_sum_inc_deleted = (float) $totals_data->invoices_total_inc_deleted; + SELECT * FROM wp_zbs_transactions trans + WHERE trans.ID IN - } elseif ( zeroBSCRM_getSetting( 'feat_quotes' ) == 1 ){ + ( + 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 - // just include quotes in total - $totals_data->total_sum = (float)$totals_data->quotes_total; + ( - } + 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 - // provide formatted equivilents - if ( zeroBSCRM_getSetting( 'feat_quotes' ) == 1 ){ - - $totals_data->quotes_total_formatted = zeroBSCRM_formatCurrency( $totals_data->quotes_total ); + ) - } - if ( zeroBSCRM_getSetting( 'feat_invs' ) == 1 ){ + ) - $totals_data->invoices_total_formatted = zeroBSCRM_formatCurrency( $totals_data->invoices_total ); + */ + $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_CONTACT . ' AND zbsol_objid_to = contact.ID)'; + $extraSelect .= ')' . $transStatusQueryAdd . ') as transactions_paid_total'; - } - if ( zeroBSCRM_getSetting( 'feat_transactions' ) == 1 ){ + } - $totals_data->transactions_total_formatted = zeroBSCRM_formatCurrency( $totals_data->transactions_total ); - $totals_data->assigned_transactions_total_formatted = zeroBSCRM_formatCurrency( $totals_data->assigned_transactions_total ); + // ==== / TOTAL VALUES - } + // @phan-suppress-next-line PhanImpossibleCondition -- Phan is confused; this var is initialized at the beginning of the function. + if ( $withDND ) { - if ( isset( $totals_data->total_sum ) ){ - - $totals_data->total_sum_formatted = zeroBSCRM_formatCurrency( $totals_data->total_sum ); + // add as subquery + $extraSelect .= ',(SELECT zbsm_val FROM ' . $ZBSCRM_t['meta'] . ' WHERE zbsm_objid = contact.ID AND zbsm_key = %s AND zbsm_objtype = ' . ZBS_TYPE_CONTACT . ' LIMIT 1) dnd'; - } + // add params + $params[] = 'do-not-email'; - } else { + } - $totals_data = null; + #} ============ / PRE-QUERY =========== - } - return $totals_data; + if ( ! empty( $additional_joins ) ) { + list( $join_sql, $join_params ) = $this->DAL()->build_joins( $additional_joins, $whereCase === 'AND' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + } - } + #} Build query + $query = 'SELECT contact.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['contacts'] . ' as contact' . $joinQ; - #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} Count override + if ( $count ) { + $query = 'SELECT COUNT(contact.ID) FROM ' . $ZBSCRM_t['contacts'] . ' as contact' . $joinQ; + } - } catch (Exception $e){ + #} simplified override + if ( $simplified ) { + $query = 'SELECT contact.ID as id,CONCAT(contact.zbsc_fname," ",contact.zbsc_lname) as name,contact.zbsc_created as created, contact.zbsc_email as email FROM ' . $ZBSCRM_t['contacts'] . ' as contact' . $joinQ; + } - #} General SQL Err - $this->catchSQLError($e); + #} onlyColumns override + if ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - } + $columnStr = ''; + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + if ( ! empty( $columnStr ) ) { + $columnStr .= ','; + } + // this presumes str is db-safe? could do with sanitation? + $columnStr .= $colDBKey; - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - #} simplified override - if ($simplified){ + } - $resArr = array( - 'id' => $resDataLine->id, - 'name' => $resDataLine->name, - 'created' => $resDataLine->created, - 'email' => $resDataLine->email - ); + $query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['contacts'] . ' as contact' . $joinQ; - } else if ($onlyColumns && is_array($onlyColumnsFieldArr) && count($onlyColumnsFieldArr) > 0){ + } - // only coumns return. - $resArr = array(); - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + #} ============= WHERE ================ + + #} Add Search phrase + if ( ! empty( $searchPhrase ) ) { + + // inefficient searching all fields. Maybe get settings from user "which fields to search" + // ... and auto compile for each contact ahead of time + $searchWheres = array(); + $searchWheres['search_fullname'] = array( 'CONCAT(zbsc_prefix, " ", zbsc_fname, " ", zbsc_lname)', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_fname'] = array( 'zbsc_fname', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_lname'] = array( 'zbsc_lname', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_email'] = array( 'zbsc_email', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + + // address elements + $searchWheres['search_addr1'] = array( 'zbsc_addr1', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_addr2'] = array( 'zbsc_addr2', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_city'] = array( 'zbsc_city', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_county'] = array( 'zbsc_county', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_country'] = array( 'zbsc_country', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_postcode'] = array( 'zbsc_postcode', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_secaddr1'] = array( 'zbsc_secaddr1', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_secaddr2'] = array( 'zbsc_secaddr2', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_seccity'] = array( 'zbsc_seccity', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_seccounty'] = array( 'zbsc_seccounty', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_seccountry'] = array( 'zbsc_seccountry', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_secpostcode'] = array( 'zbsc_secpostcode', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + + // social + $searchWheres['search_tw'] = array( 'zbsc_tw', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_li'] = array( 'zbsc_li', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_fb'] = array( 'zbsc_fb', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + + // phones + // ultimately when search is refactored, we should probably store the "clean" version of the phone numbers in the database + $searchWheres['search_hometel'] = array( 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(zbsc_hometel," ",""),".",""),"-",""),"(",""),")","")', 'LIKE', '%s', '%' . ( str_replace( array( ' ', '.', '-', '(', ')' ), '', $searchPhrase ) ) . '%' ); + $searchWheres['search_worktel'] = array( 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(zbsc_worktel," ",""),".",""),"-",""),"(",""),")","")', 'LIKE', '%s', '%' . ( str_replace( array( ' ', '.', '-', '(', ')' ), '', $searchPhrase ) ) . '%' ); + $searchWheres['search_mobtel'] = array( 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(zbsc_mobtel," ",""),".",""),"-",""),"(",""),")","")', 'LIKE', '%s', '%' . ( str_replace( array( ' ', '.', '-', '(', ')' ), '', $searchPhrase ) ) . '%' ); + + // We also add this, which finds AKA emails if using email + $searchWheres['search_alias'] = array( 'ID', 'IN', '(SELECT aka_id FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_alias = %s)', $searchPhrase ); + + // 2.99.9.11 - Added ability to search custom fields (optionally) + $customFieldSearch = zeroBSCRM_getSetting( 'customfieldsearch' ); + if ( $customFieldSearch == 1 ) { + + // simplistic add + // NOTE: This IGNORES ownership of custom field lines. + // use FULLTEXT index if available (MySQL 5.6+), otherwise use fallback + if ( jpcrm_migration_table_has_index( $ZBSCRM_t['customfields'], 'search' ) ) { + $searchWheres['search_customfields'] = array( 'ID', 'IN', '(SELECT zbscf_objid FROM ' . $ZBSCRM_t['customfields'] . ' WHERE MATCH(zbscf_objval) AGAINST(%s) AND zbscf_objtype = ' . ZBS_TYPE_CONTACT . ')', $searchPhrase ); + } else { + $searchWheres['search_customfields'] = array( 'ID', 'IN', '(SELECT zbscf_objid FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objval LIKE %s AND zbscf_objtype = ' . ZBS_TYPE_CONTACT . ')', '%' . $searchPhrase . '%' ); + } + } - if (isset($resDataLine->$colDBKey)) $resArr[$colStr] = $resDataLine->$colDBKey; + // also search "company name" where assigned + $b2bMode = zeroBSCRM_getSetting( 'companylevelcustomers' ); + // OWNERSHIP TODO - next query doesn't USE OWNERSHIP!!!!: + if ( $b2bMode == 1 ) { + $searchWheres['incompanywithname'] = array( 'ID', 'IN', '(SELECT DISTINCT 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 IN (SELECT ID FROM ' . $ZBSCRM_t['companies'] . ' WHERE zbsco_name LIKE %s))', '%' . $searchPhrase . '%' ); + } - } + // This generates a query like 'zbsc_fname LIKE %s OR zbsc_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'] ) ) { - } else { - - // tidy (normal) - $resArr = $this->tidy_contact($resDataLine,$withCustomFields); + // add it + $wheres['direct'][] = array( '(' . $searchQueryArr['where'] . ')', $searchQueryArr['params'] ); - } + } + } - // Checking and fixing name clashes between custom fields and linked objects - // (e.g. custom field with slug `company` and the company linked object) - // See: https://github.com/Automattic/zero-bs-crm/issues/3477 - $this->add_name_clash_suffix_if_needed( - $resArr, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - array( - 'tags', - 'dnd', - 'company', - 'lastlog', - 'owner', - 'invoices', - 'quotes', - 'transactions', - 'tasks', - 'external_sources', - ) - ); + #} In company? #DB1LEGACY (TOMOVE -> where) + if ( ! empty( $inCompany ) && $inCompany > 0 ) { - if ($withTags){ + // 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['incompany'] = array( 'ID', 'IN', '(SELECT DISTINCT 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 = %d)', $inCompany ); - // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_CONTACT,'objid'=>$resDataLine->ID)); + } - } + #} In array (if inCompany passed, this'll currently overwrite that?! (todo2.5)) + if ( is_array( $inArr ) && count( $inArr ) > 0 ) { - if ($withDND){ + // clean for ints + $inArrChecked = array(); + foreach ( $inArr as $x ) { + $inArrChecked[] = (int) $x; + } - // retrieve :) (paranoia mode) - $dnd = -1; $potentialDND = $this->stripSlashes($this->decodeIfJSON($resDataLine->dnd)); - if ($potentialDND == "1") $dnd = 1; + // add where + $wheres['inarray'] = array( 'ID', 'IN', '(' . implode( ',', $inArrChecked ) . ')' ); - $resArr['dnd'] = $dnd; - } + } + #} Owned by + if ( ! empty( $ownedBy ) && $ownedBy > 0 ) { - // =================================================== - // ========== #} #DB1LEGACY (TOMOVE) - // == Following is all using OLD DB stuff, here until we migrate inv etc. - // =================================================== + // 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 ); - #} With most recent log? #DB1LEGACY (TOMOVE) - if ($withLastLog){ + } - // doesn't return singular, for now using arr - $potentialLogs = $this->DAL()->logs->getLogsForObj(array( + // External sources + if ( ! empty( $externalSource ) ) { - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $resDataLine->ID, - - 'incMeta' => true, + // 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_CONTACT . ' AND zbss_source = %s)', $externalSource ); - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1 + } - )); + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - if (is_array($potentialLogs) && count($potentialLogs) > 0) $resArr['lastlog'] = $potentialLogs[0]; + // quick addition for mike + #} olderThan + if ( ! empty( $olderThan ) && $olderThan > 0 ) { + $wheres['olderThan'] = array( 'zbsc_created', '<=', '%d', $olderThan ); + } + #} newerThan + if ( ! empty( $newerThan ) && $newerThan > 0 ) { + $wheres['newerThan'] = array( 'zbsc_created', '>=', '%d', $newerThan ); + } - // CONTACT logs specifically - // doesn't return singular, for now using arr - $potentialLogs = $this->DAL()->logs->getLogsForObj( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - array( + // status + if ( ! empty( $hasStatus ) ) { + $wheres['hasStatus'] = array( 'zbsc_status', '=', '%s', $hasStatus ); + } + if ( ! empty( $otherStatus ) ) { + $wheres['otherStatus'] = array( 'zbsc_status', '<>', '%s', $otherStatus ); + } - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $resDataLine->ID, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + #} contactedBefore + if ( ! empty( $contactedBefore ) && $contactedBefore > 0 ) { + $wheres['contactedBefore'] = array( 'zbsc_lastcontacted', '<=', '%d', $contactedBefore ); + } + #} contactedAfter + if ( ! empty( $contactedAfter ) && $contactedAfter > 0 ) { + $wheres['contactedAfter'] = array( 'zbsc_lastcontacted', '>=', '%d', $contactedAfter ); + } - 'notetypes' => $zbs->DAL->logs->contact_log_types, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + #} hasEmail + if ( ! empty( $hasEmail ) ) { + $wheres['hasEmail'] = array( 'zbsc_email', '=', '%s', $hasEmail ); + $wheres['hasEmailAlias'] = array( 'ID', 'IN', '(SELECT aka_id FROM ' . $ZBSCRM_t['aka'] . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_alias = %s)', $hasEmail ); + } - 'incMeta' => true, + #} inCounty + if ( ! empty( $inCounty ) ) { + $wheres['inCounty'] = array( 'zbsc_county', '=', '%s', $inCounty ); + $wheres['inCountyAddr2'] = array( 'zbsc_secaddrcounty', '=', '%s', $inCounty ); + } + #} inPostCode + if ( ! empty( $inPostCode ) ) { + $wheres['inPostCode'] = array( 'zbsc_postcode', '=', '%s', $inPostCode ); + $wheres['inPostCodeAddr2'] = array( 'zbsc_secaddrpostcode', '=', '%s', $inPostCode ); + } + #} inCountry + if ( ! empty( $inCountry ) ) { + $wheres['inCountry'] = array( 'zbsc_country', '=', '%s', $inCountry ); + $wheres['inCountryAddr2'] = array( 'zbsc_secaddrcountry', '=', '%s', $inCountry ); + } + #} notInCounty + if ( ! empty( $notInCounty ) ) { + $wheres['notInCounty'] = array( 'zbsc_county', '<>', '%s', $notInCounty ); + $wheres['notInCountyAddr2'] = array( 'zbsc_secaddrcounty', '<>', '%s', $notInCounty ); + } + #} notInPostCode + if ( ! empty( $notInPostCode ) ) { + $wheres['notInPostCode'] = array( 'zbsc_postcode', '<>', '%s', $notInPostCode ); + $wheres['notInPostCodeAddr2'] = array( 'zbsc_secaddrpostcode', '<>', '%s', $notInPostCode ); + } + #} notInCountry + if ( ! empty( $notInCountry ) ) { + $wheres['notInCountry'] = array( 'zbsc_country', '<>', '%s', $notInCountry ); + $wheres['notInCountryAddr2'] = array( 'zbsc_secaddrcountry', '<>', '%s', $notInCountry ); + } - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 1, + // generic obj links, e.g. quotes, invs, trans + // e.g. contact(s) assigned to inv 123 + // Where the link relationship is OBJECT -> CONTACT + if ( ! empty( $hasObjIDLinkedTo ) && $hasObjIDLinkedTo > 0 && + ! empty( $hasObjTypeLinkedTo ) && $hasObjTypeLinkedTo > 0 ) { + $wheres['hasObjIDLinkedTo'] = array( 'ID', 'IN', '(SELECT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = %d AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_from = %d AND zbsol_objid_to = contact.ID)', array( $hasObjTypeLinkedTo, $hasObjIDLinkedTo ) ); - ) - ); + } - if (is_array($potentialLogs) && count($potentialLogs) > 0) $resArr['lastcontactlog'] = $potentialLogs[0]; + // generic obj links, e.g. companies + // Where the link relationship is CONTACT -> OBJECT + if ( ! empty( $isLinkedToObjID ) && $isLinkedToObjID > 0 && + ! empty( $isLinkedToObjType ) && $isLinkedToObjType > 0 ) { + $wheres['isLinkedToObjID'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objtype_to = %d AND zbsol_objid_from = contact.ID AND zbsol_objid_to = %d)', array( $isLinkedToObjType, $isLinkedToObjID ) ); + } + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } + // Any additionalWhereArr? + if ( is_array( $additionalWhereArr ) && count( $additionalWhereArr ) > 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - #} With Assigned? - if ($withOwner){ + // add em onto wheres (note these will OVERRIDE if using a key used above) + // Needs to be multi-dimensional $wheres = array_merge($wheres,$additionalWhereArr); + $wheres = array_merge_recursive( $wheres, $additionalWhereArr ); - $resArr['owner'] = zeroBS_getOwner($resDataLine->ID,true,'zerobs_customer',$resDataLine->zbs_owner); + } - } + #} Quick filters - adapted from DAL1 (probs can be slicker) + if ( is_array( $quickFilters ) && count( $quickFilters ) > 0 ) { - if ($withAssigned){ + // cycle through + foreach ( $quickFilters as $qFilter ) { - /* This is for MULTIPLE (e.g. multi companies assigned to a contact) + // where status = x + // USE hasStatus above now... + if ( str_starts_with( $qFilter, 'status_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add all assigned companies - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + $quick_filter_status = substr( $qFilter, 7 ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $wheres['quickfilterstatus'] = array( 'zbsc_status', '=', 'convert(%s using utf8mb4) collate utf8mb4_bin', $quick_filter_status ); - .. but we use 1:1, at least now: */ + } elseif ( $qFilter === 'assigned_to_me' ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $wheres['assigned_to_me'] = array( 'zbs_owner', '=', zeroBSCRM_user() ); - // add all assigned companies - $resArr['company'] = $zbs->DAL->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_CONTACT, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + } elseif ( $qFilter === 'not_assigned' ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $wheres['not_assigned'] = array( 'zbs_owner', '<=', '0' ); - - } + } elseif ( str_starts_with( $qFilter, 'notcontactedin' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ($withInvoices){ - - #} only gets first 100? - //DAL3 ver, more perf, gets all - $resArr['invoices'] = $zbs->DAL->invoices->getInvoices(array( + // check + $notcontactedinDays = (int) substr( $qFilter, 14 ); + $notcontactedinDaysSeconds = $notcontactedinDays * 86400; + $wheres['notcontactedinx'] = array( 'zbsc_lastcontacted', '<', '%d', time() - $notcontactedinDaysSeconds ); - 'assignedContact' => $resDataLine->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE), - 'sortByField' => 'ID', - 'sortOrder' => 'DESC' + } elseif ( str_starts_with( $qFilter, 'olderthan' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - )); + // check + $olderThanDays = (int) substr( $qFilter, 9 ); + $olderThanDaysSeconds = $olderThanDays * 86400; + $wheres['olderthanx'] = array( 'zbsc_created', '<', '%d', time() - $olderThanDaysSeconds ); - } + } elseif ( str_starts_with( $qFilter, 'segment_' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ($withQuotes){ - - //DAL3 ver, more perf, gets all - $resArr['quotes'] = $zbs->DAL->quotes->getQuotes(array( + // a SEGMENT + $qFilterSegmentSlug = substr( $qFilter, 8 ); - 'assignedContact' => $resDataLine->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE), - 'sortByField' => 'ID', - 'sortOrder' => 'DESC' + #} Retrieve segment + conditions + $segment = $this->DAL()->segments->getSegmentBySlug( $qFilterSegmentSlug, true, false ); + $conditions = array(); + if ( isset( $segment['conditions'] ) ) { + $conditions = $segment['conditions']; + } + $matchType = 'all'; + if ( isset( $segment['matchtype'] ) ) { + $matchType = $segment['matchtype']; + } - )); + // retrieve getContacts arguments from a list of segment conditions + // as at launch of segments (26/6/18) - these are all $additionalWhere args + // ... if it stays that way, this is nice and simple, so going to proceed with that. + // be aware if $this->segmentConditionArgs() changes, will affect this. + $contactGetArgs = $this->DAL()->segments->segmentConditionsToArgs( $conditions, $matchType ); + + // as at above, contactGetArgs should have this: + if ( isset( $contactGetArgs['additionalWhereArr'] ) && is_array( $contactGetArgs['additionalWhereArr'] ) ) { + + // This was required to work with OR and AND situs, along with the usual getContacts vars as well + // ----------------------- + // match type ALL is default, this switches to ANY + $segmentOperator = 'AND'; + if ( $matchType == 'one' ) { + $segmentOperator = 'OR'; + } - } + // This generates a query like 'zbsc_fname LIKE %s OR/AND zbsc_lname LIKE %s', + // which we then need to include as direct subquery (below) in main query :) + $segmentQueryArr = $this->buildWheres( $contactGetArgs['additionalWhereArr'], '', array(), $segmentOperator, false ); - #} ... brutal for mvp #DB1LEGACY (TOMOVE) - if ($withTransactions){ - - //DAL3 ver, more perf, gets all - $resArr['transactions'] = $zbs->DAL->transactions->getTransactions(array( + if ( is_array( $segmentQueryArr ) && isset( $segmentQueryArr['where'] ) && ! empty( $segmentQueryArr['where'] ) ) { - 'assignedContact' => $resDataLine->ID, // assigned to company id (int) - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION), - 'sortByField' => 'ID', - 'sortOrder' => 'DESC' + // add it + $wheres['direct'][] = array( '(' . $segmentQueryArr['where'] . ')', $segmentQueryArr['params'] ); - )); + } + // ----------------------- - } + // following didn't work for OR situations: (worked for most situations though, is a shame) + // ----------------------- + // so we MERGE that into our wheres... :o + // this'll override any settings above. + // Needs to be multi-dimensional + // $wheres = array_merge_recursive($wheres,$contactGetArgs['additionalWhereArr']); + // ----------------------- - #} ... brutal for mvp #DB1LEGACY (TOMOVE) - if ($withTasks){ - - //DAL3 ver, more perf, gets all - $res['tasks'] = $zbs->DAL->events->getEvents(array( + } elseif ( ! empty( $contactGetArgs['additional_joins'] ) && is_array( $contactGetArgs['additional_joins'] ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, - 'assignedContact' => $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 - - )); - - } - - // simplistic, could be optimised (though low use means later.) - if ( $withExternalSources ){ - - $res['external_sources'] = $zbs->DAL->contacts->getExternalSourcesForContact(array( - - 'contactID'=> $resDataLine->ID, - - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) - - )); - - } - if ( $withExternalSourcesGrouped ){ - - $res['external_sources'] = $zbs->DAL->getExternalSources( -1, array( - - 'objectID' => $resDataLine->ID, - 'objectType' => ZBS_TYPE_CONTACT, - 'grouped_by_source' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) - - )); - - } + list( $join_sql, $join_params ) = $this->DAL()->build_joins( $contactGetArgs['additional_joins'], $matchType === 'all' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } + } else { - //} + // normal/hardtyped - // =================================================== - // ========== / #DB1LEGACY (TOMOVE) - // =================================================== + switch ( $qFilter ) { + case 'lead': + // hack "leads only" - adapted from DAL1 (probs can be slicker) + $wheres['quickfilterlead'] = array( 'zbsc_status', 'LIKE', '%s', 'Lead' ); - $res[] = $resArr; + break; - } - } + case 'customer': + // hack - adapted from DAL1 (probs can be slicker) + $wheres['quickfiltercustomer'] = array( 'zbsc_status', 'LIKE', '%s', 'Customer' ); - return $res; - } + break; + default: + // if we've hit no filter query, let external logic hook in to provide alternatives + // First used in WooSync module + $wheres = apply_filters( 'jpcrm_contact_query_quickfilter', $wheres, $qFilter ); + break; - /** - * adds or updates a contact object - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateContact($args=array()){ + } // / switch - global $ZBSCRM_t,$wpdb,$zbs; - - #} Retrieve any cf - $customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_CONTACT)); - $addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); + } // / hardtyped - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } + } // / quickfilters - 'id' => -1, - 'owner' => -1, + #} Is Tagged (expects 1 tag ID OR array) - // fields (directly) - 'data' => array( + // catch 1 item arr + if ( is_array( $isTagged ) && count( $isTagged ) == 1 ) { + $isTagged = $isTagged[0]; + } - 'email' => '', // Unique Field ! + if ( ! empty( $isTagged ) && ! is_array( $isTagged ) && $isTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - 'status' => '', - 'prefix' => '', - 'fname' => '', - 'lname' => '', - 'addr1' => '', - 'addr2' => '', - 'city' => '', - 'county' => '', - 'country' => '', - 'postcode' => '', - 'secaddr1' => '', - 'secaddr2' => '', - 'seccity' => '', - 'seccounty' => '', - 'seccountry' => '', - 'secpostcode' => '', - 'hometel' => '', - 'worktel' => '', - 'mobtel' => '', - 'wpid' => -1, - 'avatar' => '', + // add where tagged + // 1 int: + $wheres['direct'][] = 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, $isTagged ) ); - // social basics :) - 'tw' => '', - 'fb' => '', - 'li' => '', + } elseif ( is_array( $isTagged ) && count( $isTagged ) > 0 ) { - // Note Custom fields may be passed here, but will not have defaults so check isset() + // foreach in array :) + $tagStr = ''; + foreach ( $isTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - // tags - 'tags' => -1, // pass an array of tag ids or tag strings - 'tag_mode' => 'replace', // replace|append|remove + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = contact.ID AND zbstl_tagid IN (%s)) > 0)', array( ZBS_TYPE_CONTACT, $tagStr ) ); - 'companies' => -1, // array of co id's :) + } + } + #} Is NOT Tagged (expects 1 tag ID OR array) + // catch 1 item arr + if ( is_array( $isNotTagged ) && count( $isNotTagged ) == 1 ) { + $isNotTagged = $isNotTagged[0]; + } - // wh added for later use. - 'lastcontacted' => -1, - // allow this to be set for MS sync etc. - 'created' => -1, + if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // add/update aliases - 'aliases' => -1, // array of email strings (will be verified) + // add where tagged + // 1 int: + $wheres['direct'][] = 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, $isNotTagged ) ); - ), + } elseif ( is_array( $isNotTagged ) && count( $isNotTagged ) > 0 ) { - '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 in array :) + $tagStr = ''; + foreach ( $isNotTagged as $iTag ) { + $i = (int) $iTag; + if ( $i > 0 ) { - // this function as DAL1 func did. - 'extraMeta' => -1, - 'automatorPassthrough' => -1, - 'fallBackLog' => -1, + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newContact (because is migrating, not creating new :) this was -1 before + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = contact.ID AND zbstl_tagid IN (%s)) = 0)', array( ZBS_TYPE_CONTACT, $tagStr ) ); + } + } - 'do_not_update_blanks' => false // this allows you to not update fields if blank (same as fieldoverride for extsource -> in) + #} ============ / 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]; } } } - - // Needs this to grab custom fields (if passed) too :) - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + #} ============ SORT ============== - // only for data, limited fields below - if (is_array($data)) { + // latest log + // Latest Contact Log (as sort) needs an additional SQL where str: + $contact_log_types_str = ''; + $sort_function = 'MAX'; + if ( $sortOrder !== 'DESC' ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $sort_function = 'MIN'; + } + // @phan-suppress-next-line PhanImpossibleCondition -- This var is initialized by arbitrary data in $args. + if ( $withLastLog ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if (isset($args['data'][$cK])) $data[$cK] = $args['data'][$cK]; + // retrieve log types to include + $contact_log_types = $zbs->DAL->logs->contact_log_types; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - } + // build sql + if ( is_array( $contact_log_types ) ) { + // create escaped csv + $contact_log_types_str = $this->build_csv( $contact_log_types ); + } + } - } + // 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 specific sort cases + // Note: Prefix here is a legacy leftover from the fact the AJAX List view retrieve goes through zeroBS_getCustomers() which prefixes zbsc_ + $sort_map = array( + 'zbsc_id' => 'ID', + 'zbsc_owner' => 'zbs_owner', + 'zbsc_zbs_owner' => 'zbs_owner', + + // company (name) + 'zbsc_company' => '(SELECT zbsco_name FROM ' . $ZBSCRM_t['companies'] . ' WHERE ID IN (SELECT DISTINCT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objtype_to = ' . ZBS_TYPE_COMPANY . ' AND zbsol_objid_from = contact.ID) ORDER BY zbsco_name ' . $sortOrder . ' LIMIT 0,1)', // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + + // sort by subquery: Logs + // sort by latest log is effectively 'sort by last log added' + 'zbsc_latestlog' => '(SELECT ' . $sort_function . '(zbsl_created) FROM ' . $ZBSCRM_t['logs'] . ' WHERE zbsl_objid = contact.ID AND zbsl_objtype = ' . ZBS_TYPE_CONTACT . ')', // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // sort by latest contact log is effectively 'sort by last contact log added' (requires $withLastLog = true) + 'zbsc_lastcontacted' => '(SELECT ' . $sort_function . '(zbsl_created) FROM ' . $ZBSCRM_t['logs'] . ' WHERE zbsl_objid = contact.ID AND zbsl_objtype = ' . ZBS_TYPE_CONTACT . ' AND zbsl_type IN (' . $contact_log_types_str . '))', // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + + // has & counts (same queries) + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', + 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', + 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', + 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', + 'zbsc_invoicecount_inc_deleted' => '(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_CONTACT . ' AND zbsol_objid_to = contact.ID))', + 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID)' . $inv_status_query_add . ')', + 'zbsc_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_CONTACT . ' AND zbsol_objid_to = contact.ID))', + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // following will only work if obj total value subqueries triggered above ^ + 'zbsc_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) + 'zbsc_transactiontotal' => 'transactions_total', + 'zbsc_quotetotal' => 'quotes_total', + 'zbsc_invoicetotal' => 'invoices_total', + ); + + // either from $sort_map, or multi-dimensional name search + if ( array_key_exists( $sortByField, $sort_map ) ) { + + $sortByField = $sort_map[ $sortByField ]; + + } elseif ( $sortByField === 'zbsc_fullname' || $sortByField === 'fullname' ) { + + $sortByField = array( + 'zbsc_lname' => $sortOrder, + 'zbsc_fname' => $sortOrder, + ); - /* NOT REQ: // Needs this to grab custom addr fields (if passed) too :) - if (is_array($addrCustomFields)) foreach ($addrCustomFields as $cK => $cF){ + } - // only for data, limited fields below - if (is_array($data)) { + #} ============ / SORT ============== - //if (isset($args['data'][$cK])) $data[$cK] = $args['data'][$cK]; + #} 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 - } */ + $query .= $join_sql; - // this takes limited fields + checks through for custom fields present - // (either as key zbsc_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 ( ! empty( $join_sql ) ) { + $params = array_merge( $params, $join_params ); + } - //$customFieldKeys = array_keys($customFields); - $newLimitedFields = 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 ); - // cycle through - foreach ($limitedFields as $field){ + try { - // some weird case where getting empties, so added check - if (isset($field['key']) && !empty($field['key'])){ + // Prep & run query + $queryObj = $this->prepare( $query, $params ); - $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ( str_starts_with( $field['key'], 'zbsc_' ) ) { - $dePrefixed = substr( $field['key'], strlen( 'zbsc_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + // Catch count + return if requested + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } - if (isset($customFields[$field['key']])){ + // Totals override + // This is non-performant, and shouldn't run when we've got extra joins (e.g. from segments). + if ( $onlyObjTotals && empty( $join_sql ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - // is custom, move to data - $data[$field['key']] = $field['val']; + $contact_query = 'SELECT contact.ID FROM ' . $ZBSCRM_t['contacts'] . ' AS contact' . $joinQ . $this->buildWhereStr( $whereStr, $additionalWhere ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $contact_query = $this->prepare( $contact_query, $params ); - } else if (!empty($dePrefixed) && isset($customFields[$dePrefixed])){ + $query = 'SELECT '; - // is custom, move to data - $data[$dePrefixed] = $field['val']; + if ( zeroBSCRM_getSetting( 'feat_quotes' ) == 1 ) { - } else { + $query .= '(SELECT SUM(q.zbsq_value) + FROM ' . $ZBSCRM_t['quotes'] . ' AS q + INNER JOIN ' . $ZBSCRM_t['objlinks'] . ' AS ol + ON q.ID = ol.zbsol_objid_from + WHERE + ol.zbsol_objtype_from = ' . ZBS_TYPE_QUOTE . ' + AND ol.zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' + AND ol.zbsol_objid_to IN ( ' . $contact_query . ' )) AS quotes_total'; - // add it to limitedFields (it's not dealt with post-update) - $newLimitedFields[] = $field; - } + } - } + if ( zeroBSCRM_getSetting( 'feat_invs' ) == 1 ) { - } + // if previous query, add comma + if ( $query !== 'SELECT ' ) { + $query .= ', '; + } - // move this back in - $limitedFields = $newLimitedFields; - unset($newLimitedFields); + // 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(); - } + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $query .= '(SELECT SUM(i.zbsi_total) + FROM ' . $ZBSCRM_t['invoices'] . ' AS i + INNER JOIN ' . $ZBSCRM_t['objlinks'] . ' AS ol + ON i.ID = ol.zbsol_objid_from + WHERE + ol.zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' + AND ol.zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' + AND ol.zbsol_objid_to IN ( ' . $contact_query . ' ) ' . $inv_status_query_add . ') AS invoices_total,'; - #} =========== / LOAD ARGS ============ + $query .= '(SELECT SUM(inc_deleted_invoices.zbsi_total) + FROM ' . $ZBSCRM_t['invoices'] . ' AS inc_deleted_invoices + INNER JOIN ' . $ZBSCRM_t['objlinks'] . ' AS ol + ON inc_deleted_invoices.ID = ol.zbsol_objid_from + WHERE + ol.zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' + AND ol.zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' + AND ol.zbsol_objid_to IN ( ' . $contact_query . ' )) AS invoices_total_inc_deleted'; + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - #} ========== CHECK FIELDS ============ - - $id = (int)$id; - - // here we check that the potential owner CAN even own - if ( - // specified owner is not an admin - !user_can($owner,'admin_zerobs_usr') - ) { - $owner = -1; - } + if ( zeroBSCRM_getSetting( 'feat_transactions' ) == 1 ) { + // if previous query, add comma + if ( $query !== 'SELECT ' ) { + $query .= ', '; + } - if (is_array($limitedFields)){ + // only include transactions with statuses which should be included in total value: + $transaction_status_query_addition = $this->DAL()->transactions->getTransactionStatusesToIncludeQuery(); + + $query .= '(SELECT SUM(t.zbst_total) + FROM ' . $ZBSCRM_t['transactions'] . ' AS t + INNER JOIN ' . $ZBSCRM_t['objlinks'] . ' AS ol + ON t.ID = ol.zbsol_objid_from + WHERE + ol.zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION . ' + AND ol.zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' + AND ol.zbsol_objid_to IN ( ' . $contact_query . ' ) ' . $transaction_status_query_addition . ') AS transactions_total, '; + + $query .= '(SELECT SUM(assigned_transactions.zbst_total) + FROM ' . $ZBSCRM_t['transactions'] . ' AS assigned_transactions + WHERE assigned_transactions.ID IN + ( + 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 + ( + SELECT DISTINCT zbsol_objid_from + FROM ' . $ZBSCRM_t['objlinks'] . ' + WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND + zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND + zbsol_objid_to IN ( ' . $contact_query . ' ) + ) + )) AS assigned_transactions_total'; - // LIMITED UPDATE (only a few fields.) - // phpcs:ignore - if ( count( $limitedFields ) === 0 ) { - return false; } - // REQ. ID too (can only update) - if (empty($id) || $id <= 0) return false; - - } else { - // NORMAL, FULL UPDATE + if ( $query !== 'SELECT ' ) { - // check email + load that user if present - if (!isset($data['email']) || empty($data['email'])){ + $totals_data = $wpdb->get_row( $query ); - // no email - // Allow users without emails? WH removed this for db1->2 migration - // leaving this in breaks MIGRATIONS from DAL 1 - // in that those contacts without emails will not be copied in - // return false; + if ( zeroBSCRM_getSetting( 'feat_invs' ) == 1 && zeroBSCRM_getSetting( 'feat_transactions' ) == 1 ) { - } else { + // calculate a total sum (invoices + unassigned transactions) + $totals_data->total_sum = (float) $totals_data->invoices_total + (float) $totals_data->transactions_total - (float) $totals_data->assigned_transactions_total; + // total_sum_inc_deleted currently factors in deleted invoices + $totals_data->total_sum_inc_deleted = (float) $totals_data->invoices_total_inc_deleted + (float) $totals_data->transactions_total - (float) $totals_data->assigned_transactions_total; - // email present, check if it matches ID? - if (!empty($id) && $id > 0){ + } elseif ( zeroBSCRM_getSetting( 'feat_invs' ) == 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->getContact(-1,array('email'=>$data['email'],'ignoreOwner'=>1,'onlyID'=>1)); - if (!empty($potentialUSERID) && $potentialUSERID > 0 && $id > 0 && $potentialUSERID != $id){ + // just include invoices in total + $totals_data->total_sum = (float) $totals_data->invoices_total; + $totals_data->total_sum_inc_deleted = (float) $totals_data->invoices_total_inc_deleted; - // email doesn't match ID - return false; - } + } elseif ( zeroBSCRM_getSetting( 'feat_quotes' ) == 1 ) { - // also check if has rights?!? Could be just email passed here + therefor got around owner check? hmm. + // just include quotes in total + $totals_data->total_sum = (float) $totals_data->quotes_total; - } else { + } - // no ID, check if email present, and then update that user if so - $potentialUSERID = (int)$this->getContact(-1,array('email'=>$data['email'],'ignoreOwner'=>1,'onlyID'=>1)); - if (isset($potentialUSERID) && !empty($potentialUSERID) && $potentialUSERID > 0) { $id = $potentialUSERID; } + // provide formatted equivilents + if ( zeroBSCRM_getSetting( 'feat_quotes' ) == 1 ) { - } + $totals_data->quotes_total_formatted = zeroBSCRM_formatCurrency( $totals_data->quotes_total ); + } + if ( zeroBSCRM_getSetting( 'feat_invs' ) == 1 ) { - } + $totals_data->invoices_total_formatted = zeroBSCRM_formatCurrency( $totals_data->invoices_total ); + } + if ( zeroBSCRM_getSetting( 'feat_transactions' ) == 1 ) { - // companies - if (isset($data['companies']) && is_array($data['companies'])){ + $totals_data->transactions_total_formatted = zeroBSCRM_formatCurrency( $totals_data->transactions_total ); + $totals_data->assigned_transactions_total_formatted = zeroBSCRM_formatCurrency( $totals_data->assigned_transactions_total ); + } - $coArr = array(); - /* - there was a bug happening here where same company could get dude at a few times... - so for now only use the first company */ - /* - foreach ($data['companies'] as $c){ - $cI = (int)$c; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; - }*/ + if ( isset( $totals_data->total_sum ) ) { - $cI = (int)$data['companies'][0]; - if ($cI > 0 && !in_array($cI, $coArr)) $coArr[] = $cI; + $totals_data->total_sum_formatted = zeroBSCRM_formatCurrency( $totals_data->total_sum ); - // reset the main - if (count($coArr) > 0) - $data['companies'] = $coArr; - else - $data['companies'] = 'unset'; - unset($coArr); + } + } else { - } + $totals_data = null; + } + return $totals_data; - } + } - // If no status passed or previously set, use the default status - if ( empty($data['status'] ) ) { + #} else continue.. + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - // copy any previously set - $data['status'] = $this->getContactStatus($id); - - // if not previously set, use default - if (empty($data['status'])) $data['status'] = zeroBSCRM_getSetting('defaultstatus'); + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - #} ========= / CHECK FIELDS =========== + } + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - #} ========= OVERRIDE SETTING (Deny blank overrides) =========== + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - // 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"){ + #} simplified override + if ( $simplified ) { - $do_not_update_blanks = true; + $resArr = array( + 'id' => $resDataLine->id, + 'name' => $resDataLine->name, + 'created' => $resDataLine->created, + 'email' => $resDataLine->email, + ); - } + } elseif ( $onlyColumns && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - } + // only coumns return. + $resArr = array(); + foreach ( $onlyColumnsFieldArr as $colDBKey => $colStr ) { - // either ext source + setting, or set by the func call - if ( $do_not_update_blanks ) { + if ( isset( $resDataLine->$colDBKey ) ) { + $resArr[ $colStr ] = $resDataLine->$colDBKey; + } + } + } else { - // 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){ + // tidy (normal) + $resArr = $this->tidy_contact( $resDataLine, $withCustomFields ); - // get data to copy over (for now, this is required to remove 'fullname' etc.) - $dbData = $this->db_ready_contact($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'=>'zbsc_x','val'=>y,'type'=>'%s')) + // Checking and fixing name clashes between custom fields and linked objects + // (e.g. custom field with slug `company` and the company linked object) + // See: https://github.com/Automattic/zero-bs-crm/issues/3477 + $this->add_name_clash_suffix_if_needed( + $resArr, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + array( + 'tags', + 'dnd', + 'company', + 'lastlog', + 'owner', + 'invoices', + 'quotes', + 'transactions', + 'tasks', + 'external_sources', + ) + ); - // 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){ + if ( $withTags ) { - $intV = (int)$v; + // add all tags lines + $resArr['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_CONTACT, + 'objid' => $resDataLine->ID, + ) + ); - // 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' => 'zbsc_'.$k, // we have to add zbsc_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbsc_'.$k) - ); + if ( $withDND ) { - // add to remade $data for post-update updates - $data[$k] = $v; + // retrieve :) (paranoia mode) + $dnd = -1; + $potentialDND = $this->stripSlashes( $this->decodeIfJSON( $resDataLine->dnd ) ); + if ( $potentialDND == '1' ) { + $dnd = 1; + } - } + $resArr['dnd'] = $dnd; + } - } + // =================================================== + // ========== #} #DB1LEGACY (TOMOVE) + // == Following is all using OLD DB stuff, here until we migrate inv etc. + // =================================================== - // copy over - $limitedFields = $limitedData; + #} With most recent log? #DB1LEGACY (TOMOVE) + if ( $withLastLog ) { - } // / if ID + // doesn't return singular, for now using arr + $potentialLogs = $this->DAL()->logs->getLogsForObj( + array( - } // / if do_not_update_blanks + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $resDataLine->ID, - // ========= / OVERRIDE SETTING (Deny blank overrides) =========== + 'incMeta' => true, - // ========= BUILD DATA =========== + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, - // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase -- to be refactoerd later. - $update = false; - $dataArr = array(); - $typeArr = array(); - $contactsPreUpdateSegments = array(); + ) + ); - if ( is_array( $limitedFields ) ) { + if ( is_array( $potentialLogs ) && count( $potentialLogs ) > 0 ) { + $resArr['lastlog'] = $potentialLogs[0]; + } - // LIMITED FIELDS - $update = true; + // CONTACT logs specifically + // doesn't return singular, for now using arr + $potentialLogs = $this->DAL()->logs->getLogsForObj( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + array( - // cycle through - foreach ( $limitedFields as $field ) { + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $resDataLine->ID, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // some weird case where getting empties, so added check - if ( empty( $field['key'] ) ) { - continue; - } - // Created date field is immutable. Skip. - if ( $field['key'] === 'zbsc_created' ) { - continue; - } + 'notetypes' => $zbs->DAL->logs->contact_log_types, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - $dataArr[ $field['key'] ] = $field['val']; - $typeArr[] = $field['type']; - } + 'incMeta' => true, - // add update time - if ( ! isset( $dataArr['zbsc_lastupdated'] ) ) { - $dataArr['zbsc_lastupdated'] = time(); - $typeArr[] = '%d'; - } - } else { + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 1, - // FULL UPDATE/INSERT - - // UPDATE - $dataArr = array( - - 'zbs_owner' => $owner, - - // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- to be refactored. - // fields - 'zbsc_status' => $data['status'], - 'zbsc_email' => $data['email'], - 'zbsc_prefix' => $data['prefix'], - 'zbsc_fname' => $data['fname'], - 'zbsc_lname' => $data['lname'], - 'zbsc_addr1' => $data['addr1'], - 'zbsc_addr2' => $data['addr2'], - 'zbsc_city' => $data['city'], - 'zbsc_county' => $data['county'], - 'zbsc_country' => $data['country'], - 'zbsc_postcode' => $data['postcode'], - 'zbsc_secaddr1' => $data['secaddr1'], - 'zbsc_secaddr2' => $data['secaddr2'], - 'zbsc_seccity' => $data['seccity'], - 'zbsc_seccounty' => $data['seccounty'], - 'zbsc_seccountry' => $data['seccountry'], - 'zbsc_secpostcode' => $data['secpostcode'], - 'zbsc_hometel' => $data['hometel'], - 'zbsc_worktel' => $data['worktel'], - 'zbsc_mobtel' => $data['mobtel'], - 'zbsc_wpid' => $data['wpid'], - 'zbsc_avatar' => $data['avatar'], - - 'zbsc_tw' => $data['tw'], - 'zbsc_fb' => $data['fb'], - 'zbsc_li' => $data['li'], - - 'zbsc_lastupdated' => time(), + ) ); - // if set. - if ( $data['lastcontacted'] !== -1 ) { - $dataArr['zbsc_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', - '%s', - '%s', - '%s', - '%d', - '%s', - '%s', - '%s', - '%s', - '%d', // last updated - ); - // if set - if ( $data['lastcontacted'] !== -1 ) { - $typeArr[] = '%d'; + if ( is_array( $potentialLogs ) && count( $potentialLogs ) > 0 ) { + $resArr['lastcontactlog'] = $potentialLogs[0]; } + } - if ( ! empty( $id ) && $id > 0 ) { + #} With Assigned? + if ( $withOwner ) { - // is update - $update = true; + $resArr['owner'] = zeroBS_getOwner( $resDataLine->ID, true, 'zerobs_customer', $resDataLine->zbs_owner ); - } else { + } - // INSERT (get's few extra :D) - $update = false; - $dataArr['zbs_site'] = zeroBSCRM_site(); - $typeArr[] = '%d'; - $dataArr['zbs_team'] = zeroBSCRM_team(); - $typeArr[] = '%d'; + if ( $withAssigned ) { + + /* + This is for MULTIPLE (e.g. multi companies assigned to a contact) + + // add all assigned companies + $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 companies + $resArr['company'] = $zbs->DAL->companies->getCompanies( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_CONTACT, + 'hasObjIDLinkedTo' => $resDataLine->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); - if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { - $dataArr['zbsc_created'] = $data['created']; - $typeArr[] = '%d'; - } else { - $dataArr['zbsc_created'] = time(); - $typeArr[] = '%d'; - } + } - $dataArr['zbsc_lastcontacted'] = -1; - $typeArr[] = '%d'; - } - } - #} ========= / BUILD DATA =========== + if ( $withInvoices ) { - #} ============================================================ - #} ========= CHECK force_uniques & not_empty & max_len ======== + #} only gets first 100? + // DAL3 ver, more perf, gets all + $resArr['invoices'] = $zbs->DAL->invoices->getInvoices( + array( - // 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)){ + 'assignedContact' => $resDataLine->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_INVOICE ), + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', - // 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 + } - } + if ( $withQuotes ) { - // whatever we do we check for max_len breaches and abbreviate to avoid wpdb rejections - $dataArr = $this->wpdbChecks( $dataArr ); - - // CHECK force_uniques & not_empty + // DAL3 ver, more perf, gets all + $resArr['quotes'] = $zbs->DAL->quotes->getQuotes( + array( - // Check if ID present - if ( $update ) { + 'assignedContact' => $resDataLine->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', - // Check if obj exists (here) - for now just brutal update (will error when doesn't exist) - $originalStatus = $this->getContactStatus( $id ); + ) + ); - $previous_contact_obj = $this->getContact( $id ); + } - // get any segments (whom counts may be affected by changes) - // $contactsPreUpdateSegments = $this->DAL()->segments->getSegmentsContainingContact($id,true); + #} ... brutal for mvp #DB1LEGACY (TOMOVE) + if ( $withTransactions ) { - // log any change of status - if ( isset( $dataArr['zbsc_status'] ) && ! empty( $dataArr['zbsc_status'] ) && ! empty( $originalStatus ) && $dataArr['zbsc_status'] !== $originalStatus ) { + // DAL3 ver, more perf, gets all + $resArr['transactions'] = $zbs->DAL->transactions->getTransactions( + array( - // status change - $statusChange = array( - 'from' => $originalStatus, - 'to' => $dataArr['zbsc_status'], - ); - } + 'assignedContact' => $resDataLine->ID, // assigned to company id (int) + 'page' => -1, + 'perPage' => -1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', - // Attempt update - if ($wpdb->update( - $ZBSCRM_t['contacts'], - $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'])) { + #} ... brutal for mvp #DB1LEGACY (TOMOVE) + if ( $withTasks ) { - $this->addUpdateContactTags( - array( - 'id' => $id, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + // DAL3 ver, more perf, gets all + $resArr['tasks'] = $zbs->DAL->events->getEvents( + array( - } + 'assignedContact' => $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 - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( - array( - 'obj_id' => $id, - 'obj_type_id' => ZBS_TYPE_CONTACT, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), - ) - ); // for IA below + ) + ); - // co's work? - // OBJ LINKS - to companies (1liner now as genericified) - $this->addUpdateObjectLinks($id,$data['companies'],ZBS_TYPE_COMPANY); + } + // simplistic, could be optimised (though low use means later.) + if ( $withExternalSources ) { - // Aliases - // Maintain an array of AKA emails - if (isset($data['aliases']) && is_array($data['aliases'])){ - - $existingAliasesSimple = array(); - $existingAliases = zeroBS_getObjAliases(ZBS_TYPE_CONTACT,$id); - if (!is_array($existingAliases)) $existingAliases = array(); + $resArr['external_sources'] = $zbs->DAL->contacts->getExternalSourcesForContact( + array( - // compare - if (is_array($existingAliases)) foreach ($existingAliases as $alias){ + 'contactID' => $resDataLine->ID, - // is this alias in the new list? - if (in_array($alias['aka_alias'], $data['aliases'])) { - $existingAliasesSimple[] = $alias['aka_alias']; - continue; - } + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - // it's not in the new list, thus, remove it: - // this could be a smidgen more performant if it just deleted the line - zeroBS_removeObjAlias(ZBS_TYPE_CONTACT,$id,$alias['aka_alias']); + ) + ); - } - foreach ($data['aliases'] as $alias){ + } + if ( $withExternalSourcesGrouped ) { - // valid? - if (zeroBS_canUseCustomerAlias($alias)){ + $resArr['external_sources'] = $zbs->DAL->getExternalSources( + -1, + array( - // is this alias in the existing list? (nothing to do) - if (in_array($alias, $existingAliasesSimple)) continue; + 'objectID' => $resDataLine->ID, + 'objectType' => ZBS_TYPE_CONTACT, + 'grouped_by_source' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - // it's not in the existing list, thus, add it: - zeroBS_addObjAlias(ZBS_TYPE_CONTACT,$id,$alias); + ) + ); - } else { + } - // err - tried to use an invalid alias - $msg = __('Could not add alias (unavailable or invalid):','zero-bs-crm').' '.$alias; - $zbs->DAL->addError(307,$this->objectType,$msg,$alias); + // } - } + // =================================================== + // ========== / #DB1LEGACY (TOMOVE) + // =================================================== - } + $res[] = $resArr; - } + } + } + return $res; + } + + /** + * adds or updates a contact object + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateContact( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; + + #} Retrieve any cf + $customFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_CONTACT ) ); + $addrCustomFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'owner' => -1, + + // fields (directly) + 'data' => array( + + 'email' => '', // Unique Field ! + + 'status' => '', + 'prefix' => '', + 'fname' => '', + 'lname' => '', + 'addr1' => '', + 'addr2' => '', + 'city' => '', + 'county' => '', + 'country' => '', + 'postcode' => '', + 'secaddr1' => '', + 'secaddr2' => '', + 'seccity' => '', + 'seccounty' => '', + 'seccountry' => '', + 'secpostcode' => '', + 'hometel' => '', + 'worktel' => '', + 'mobtel' => '', + 'wpid' => -1, + 'avatar' => '', + + // social basics :) + 'tw' => '', + 'fb' => '', + 'li' => '', + + // 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 :) + + 'companies' => -1, // array of co id's :) + + // wh added for later use. + 'lastcontacted' => -1, + // allow this to be set for MS sync etc. + 'created' => -1, + + // add/update aliases + 'aliases' => -1, // array of email strings (will be verified) + + ), + + '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 newContact (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 ]; + } + } + } - } // / if $data/limitedData + // 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 ) ) { - // 2.98.1+ ... custom fields should update if present, regardless of limitedData rule - // ... UNLESS BLANK! - // Custom fields? + if ( isset( $args['data'][ $cK ] ) ) { + $data[ $cK ] = $args['data'][ $cK ]; + } + } + } + } - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + /* + NOT REQ: // Needs this to grab custom addr fields (if passed) too :) + if ( is_array( $addrCustomFields)) foreach ( $addrCustomFields as $cK => $cF){ - // any? - if (isset($data[$cK])){ + // only for data, limited fields below + if ( is_array( $data) ) { - // updating blanks? - if ($do_not_update_blanks && empty($data[$cK])){ + //if (isset($args['data'][$cK])) $data[$cK] = $args['data'][$cK]; - // skip it + } - } else { + } */ - // it's either not in do_not_update_blank mode, or it has a val + // this takes limited fields + checks through for custom fields present + // (either as key zbsc_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 ) ) { - // add update - $cfID = $this->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $id, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + // $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'], 'zbsc_' ) ) { + $dePrefixed = substr( $field['key'], strlen( 'zbsc_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - // Also got to catch any 'addr' custom fields :) - if (is_array($addrCustomFields) && count($addrCustomFields) > 0){ + if ( isset( $customFields[ $field['key'] ] ) ) { - // 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){ + // is custom, move to data + $data[ $field['key'] ] = $field['val']; - // v2: - //$cKN = (int)$cK+1; - //$cKey = 'addr_cf'.$cKN; - //$cKey2 = 'secaddr_cf'.$cKN; - // v3: - $cKey = 'addr_'.$cK; - $cKey2 = 'secaddr_'.$cK; + } elseif ( ! empty( $dePrefixed ) && isset( $customFields[ $dePrefixed ] ) ) { - if (isset($data[$cKey])){ + // is custom, move to data + $data[ $dePrefixed ] = $field['val']; - // updating blanks? - if ($do_not_update_blanks && empty($data[$cKey])){ + } else { - // skip it + // add it to limitedFields (it's not dealt with post-update) + $newLimitedFields[] = $field; + } + } + } - } else { + // move this back in + $limitedFields = $newLimitedFields; + unset( $newLimitedFields ); - // it's either not in do_not_update_blank mode, or it has a val + } - // add update - $cfID = $this->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $id, - 'objkey' => $cKey, - 'objval' => $data[$cKey] - ))); + #} =========== / LOAD ARGS ============ - } + #} ========== CHECK FIELDS ============ - } + $id = (int) $id; - // any? - if (isset($data[$cKey2])){ + // here we check that the potential owner CAN even own + if ( + // specified owner is not an admin + ! user_can( $owner, 'admin_zerobs_usr' ) + ) { + $owner = -1; + } - // updating blanks? - if ($do_not_update_blanks && empty($data[$cKey2])){ + if ( is_array( $limitedFields ) ) { - // skip it + // LIMITED UPDATE (only a few fields.) + // phpcs:ignore + if ( count( $limitedFields ) === 0 ) { + return false; + } + // REQ. ID too (can only update) + if ( empty( $id ) || $id <= 0 ) { + return false; + } + } else { + + // NORMAL, FULL UPDATE + + // 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 contacts 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->getContact( + -1, + array( + 'email' => $data['email'], + 'ignoreOwner' => 1, + 'onlyID' => 1, + ) + ); + if ( ! empty( $potentialUSERID ) && $potentialUSERID > 0 && $id > 0 && $potentialUSERID != $id ) { - } else { + // email doesn't match ID + return false; + } - // it's either not in do_not_update_blank mode, or it has a val + // also check if has rights?!? Could be just email passed here + therefor got around owner check? hmm. - // add update - $cfID = $this->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $id, - 'objkey' => $cKey2, - 'objval' => $data[$cKey2] - ))); + } else { - } + // no ID, check if email present, and then update that user if so + $potentialUSERID = (int) $this->getContact( + -1, + array( + 'email' => $data['email'], + 'ignoreOwner' => 1, + 'onlyID' => 1, + ) + ); + if ( isset( $potentialUSERID ) && ! empty( $potentialUSERID ) && $potentialUSERID > 0 ) { + $id = $potentialUSERID; + } + } + } - } + // companies + if ( isset( $data['companies'] ) && is_array( $data['companies'] ) ) { + + $coArr = array(); + /* + there was a bug happening here where same company could get dude at a few times... + so for now only use the first company */ + /* + foreach ( $data['companies'] as $c){ + $cI = (int)$c; + if ( $cI > 0 && !in_array( $cI, $coArr)) $coArr[] = $cI; + }*/ + + $cI = (int) $data['companies'][0]; + 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 ); + } + } - } + // If no status passed or previously set, use the default status + if ( empty( $data['status'] ) ) { - // / Custom Fields + // copy any previously set + $data['status'] = $this->getContactStatus( $id ); - #} 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 + // if not previously set, use default + if ( empty( $data['status'] ) ) { + $data['status'] = zeroBSCRM_getSetting( 'defaultstatus' ); + } + } - $confirmedExtraMeta = array(); + #} ========= / CHECK FIELDS =========== - foreach ($extraMeta as $k => $v){ + #} ========= OVERRIDE SETTING (Deny blank overrides) =========== - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + // 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' ) { - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_CONTACT,$id,'extra_'.$cleanKey,$v); + $do_not_update_blanks = true; - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + } + } - } + // 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_contact( $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 :) - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ + $origData = $data; // $data = array(); + $limitedData = array(); // array(array('key'=>'zbsc_x','val'=>y,'type'=>'%s')) - #} 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 + 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 add, maybe validate more?! + $intV = (int) $v; - #} Long desc if present: - $zbsNoteLongDesc = ''; if (isset($fallBackLog['longdesc']) && !empty($fallBackLog['longdesc'])) $zbsNoteLongDesc = $fallBackLog['longdesc']; + // only add if valuenot empty + if ( ! is_array( $v ) && ! empty( $v ) && $v != '' && $v !== 0 && $v !== -1 && $intV !== -1 ) { - #} Only raw checked... but proceed. - $newOrUpdatedLogID = zeroBS_addUpdateContactLog($id,-1,-1,array( - #} Anything here will get wrapped into an array and added as the meta vals - 'type' => $fallBackLog['type'], - 'shortdesc' => $fallBackLog['shortdesc'], - 'longdesc' => $zbsNoteLongDesc - )); + // add to update arr + $limitedData[] = array( + 'key' => 'zbsc_' . $k, // we have to add zbsc_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbsc_' . $k ), + ); + // add to remade $data for post-update updates + $data[ $k ] = $v; - } + } + } - // catch dirty flag (update of status) (note, after update_post_meta - as separate) - //if (isset($_POST['zbsc_status_dirtyflag']) && $_POST['zbsc_status_dirtyflag'] == "1"){ - // actually here, it's set above - if (isset($statusChange) && is_array($statusChange)){ + // copy over + $limitedFields = $limitedData; - // status has changed + } // / if ID - // IA - zeroBSCRM_FireInternalAutomator('contact.status.update',array( - 'id'=>$id, - 'againstid' => $id, - 'userMeta'=> $dataArr, - 'from' => $statusChange['from'], - 'to' => $statusChange['to'] - )); + } // / if do_not_update_blanks - } + // ========= / OVERRIDE SETTING (Deny blank overrides) =========== + // ========= BUILD DATA =========== - // IA General contact update (2.87+) - zeroBSCRM_FireInternalAutomator('contact.update',array( - 'id'=>$id, - 'againstid' => $id, - 'userMeta'=> $dataArr, - 'prevSegments' => $contactsPreUpdateSegments, - 'prev_contact' => $previous_contact_obj, - )); + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase -- to be refactoerd later. + $update = false; + $dataArr = array(); + $typeArr = array(); + $contactsPreUpdateSegments = array(); - $dataArr['id'] = $id; - $this->events_manager->contact()->updated( $dataArr, $previous_contact_obj ); + 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'] ) ) { + continue; + } + // Created date field is immutable. Skip. + if ( $field['key'] === 'zbsc_created' ) { + continue; + } - // FAILED update - return false; + $dataArr[ $field['key'] ] = $field['val']; + $typeArr[] = $field['type']; + } - } + // add update time + if ( ! isset( $dataArr['zbsc_lastupdated'] ) ) { + $dataArr['zbsc_lastupdated'] = time(); + $typeArr[] = '%d'; + } + } else { + + // FULL UPDATE/INSERT + + // UPDATE + $dataArr = array( + + 'zbs_owner' => $owner, + + // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- to be refactored. + // fields + 'zbsc_status' => $data['status'], + 'zbsc_email' => $data['email'], + 'zbsc_prefix' => $data['prefix'], + 'zbsc_fname' => $data['fname'], + 'zbsc_lname' => $data['lname'], + 'zbsc_addr1' => $data['addr1'], + 'zbsc_addr2' => $data['addr2'], + 'zbsc_city' => $data['city'], + 'zbsc_county' => $data['county'], + 'zbsc_country' => $data['country'], + 'zbsc_postcode' => $data['postcode'], + 'zbsc_secaddr1' => $data['secaddr1'], + 'zbsc_secaddr2' => $data['secaddr2'], + 'zbsc_seccity' => $data['seccity'], + 'zbsc_seccounty' => $data['seccounty'], + 'zbsc_seccountry' => $data['seccountry'], + 'zbsc_secpostcode' => $data['secpostcode'], + 'zbsc_hometel' => $data['hometel'], + 'zbsc_worktel' => $data['worktel'], + 'zbsc_mobtel' => $data['mobtel'], + 'zbsc_wpid' => $data['wpid'], + 'zbsc_avatar' => $data['avatar'], + + 'zbsc_tw' => $data['tw'], + 'zbsc_fb' => $data['fb'], + 'zbsc_li' => $data['li'], + + 'zbsc_lastupdated' => time(), + ); - } else { - - #} No ID - must be an INSERT - if ($wpdb->insert( - $ZBSCRM_t['contacts'], - $dataArr, - $typeArr ) > 0){ + // if set. + if ( $data['lastcontacted'] !== -1 ) { + $dataArr['zbsc_lastcontacted'] = $data['lastcontacted']; + } - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; + $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', + '%s', + '%s', + '%s', + '%d', + '%s', + '%s', + '%s', + '%s', + '%d', // last updated + ); + // if set + if ( $data['lastcontacted'] !== -1 ) { + $typeArr[] = '%d'; + } - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + if ( ! empty( $id ) && $id > 0 ) { - $this->addUpdateContactTags( - array( - 'id' => $newID, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + // is update + $update = true; - } - - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( - array( - 'obj_id' => $newID, - 'obj_type_id' => ZBS_TYPE_CONTACT, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), - ) - ); // for IA below - - // co's work? - // OBJ LINKS - to companies (1liner now as genericified) - $this->addUpdateObjectLinks($newID,$data['companies'],ZBS_TYPE_COMPANY); - /* - if (isset($data['companies']) && is_array($data['companies']) && count($data['companies']) > 0) - $this->DAL()->addUpdateObjLinks(array( - 'objtypefrom' => ZBS_TYPE_CONTACT, - 'objtypeto' => ZBS_TYPE_COMPANY, - 'objfromid' => $newID, - 'objtoids' => $data['companies'])); - */ - - - // Aliases - // Maintain an array of AKA emails - if (isset($data['aliases']) && is_array($data['aliases'])){ - - $existingAliasesSimple = array(); - $existingAliases = zeroBS_getObjAliases(ZBS_TYPE_CONTACT,$newID); - if (!is_array($existingAliases)) $existingAliases = array(); - - // compare - if (is_array($existingAliases)) foreach ($existingAliases as $alias){ - - // is this alias in the new list? - if (in_array($alias['aka_alias'], $data['aliases'])) { - $existingAliasesSimple[] = $alias['aka_alias']; - continue; - } - - // it's not in the new list, thus, remove it: - // this could be a smidgen more performant if it just deleted the line - zeroBS_removeObjAlias(ZBS_TYPE_CONTACT,$newID,$alias['aka_alias']); + } else { - } - foreach ($data['aliases'] as $alias){ + // INSERT (get's few extra :D) + $update = false; + $dataArr['zbs_site'] = zeroBSCRM_site(); + $typeArr[] = '%d'; + $dataArr['zbs_team'] = zeroBSCRM_team(); + $typeArr[] = '%d'; - // valid? - if (zeroBS_canUseCustomerAlias($alias)){ + if ( isset( $data['created'] ) && ! empty( $data['created'] ) && $data['created'] !== -1 ) { + $dataArr['zbsc_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbsc_created'] = time(); + $typeArr[] = '%d'; + } - // is this alias in the existing list? (nothing to do) - if (in_array($alias, $existingAliasesSimple)) continue; + $dataArr['zbsc_lastcontacted'] = -1; + $typeArr[] = '%d'; + } + } + #} ========= / BUILD DATA =========== - // it's not in the existing list, thus, add it: - zeroBS_addObjAlias(ZBS_TYPE_CONTACT,$newID,$alias); + #} ============================================================ + #} ========= CHECK force_uniques & not_empty & max_len ======== - } else { + // 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 ) ) { - // err - tried to use an invalid alias - $msg = __('Could not add alias (unavailable or invalid):','zero-bs-crm').' '.$alias; - $zbs->DAL->addError(307,$this->objectType,$msg,$alias); + // 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 ) { - #} Cycle through + add/update if set - if (is_array($customFields)) foreach ($customFields as $cK => $cF){ + // Check if obj exists (here) - for now just brutal update (will error when doesn't exist) + $originalStatus = $this->getContactStatus( $id ); - // any? - if (isset($data[$cK])){ + $previous_contact_obj = $this->getContact( $id ); - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $newID, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + // get any segments (whom counts may be affected by changes) + // $contactsPreUpdateSegments = $this->DAL()->segments->getSegmentsContainingContact($id,true); - } + // log any change of status + if ( isset( $dataArr['zbsc_status'] ) && ! empty( $dataArr['zbsc_status'] ) && ! empty( $originalStatus ) && $dataArr['zbsc_status'] !== $originalStatus ) { - } - + // status change + $statusChange = array( + 'from' => $originalStatus, + 'to' => $dataArr['zbsc_status'], + ); + } - // Also got to catch any 'addr' custom fields :) - if (is_array($addrCustomFields) && count($addrCustomFields) > 0){ + // Attempt update + if ( $wpdb->update( + $ZBSCRM_t['contacts'], + $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->addUpdateContactTags( + array( + 'id' => $id, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); - // 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; + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $id, + 'obj_type_id' => ZBS_TYPE_CONTACT, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below + + // co's work? + // OBJ LINKS - to companies (1liner now as genericified) + $this->addUpdateObjectLinks( $id, $data['companies'], ZBS_TYPE_COMPANY ); + + // Aliases + // Maintain an array of AKA emails + if ( isset( $data['aliases'] ) && is_array( $data['aliases'] ) ) { + + $existingAliasesSimple = array(); + $existingAliases = zeroBS_getObjAliases( ZBS_TYPE_CONTACT, $id ); + if ( ! is_array( $existingAliases ) ) { + $existingAliases = array(); + } - if (isset($data[$cKey])){ + // compare + if ( is_array( $existingAliases ) ) { + foreach ( $existingAliases as $alias ) { - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $newID, - 'objkey' => $cKey, - 'objval' => $data[$cKey] - ))); + // is this alias in the new list? + if ( in_array( $alias['aka_alias'], $data['aliases'] ) ) { + $existingAliasesSimple[] = $alias['aka_alias']; + continue; + } - } + // it's not in the new list, thus, remove it: + // this could be a smidgen more performant if it just deleted the line + zeroBS_removeObjAlias( ZBS_TYPE_CONTACT, $id, $alias['aka_alias'] ); - // any? - if (isset($data[$cKey2])){ + } + } + foreach ( $data['aliases'] as $alias ) { - // add update - $cfID = $this->DAL()->addUpdateCustomField(array( - 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $newID, - 'objkey' => $cKey2, - 'objval' => $data[$cKey2] - ))); + // valid? + if ( zeroBS_canUseCustomerAlias( $alias ) ) { - } - // phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + // is this alias in the existing list? (nothing to do) + if ( in_array( $alias, $existingAliasesSimple ) ) { + continue; + } + // it's not in the existing list, thus, add it: + zeroBS_addObjAlias( ZBS_TYPE_CONTACT, $id, $alias ); - } + } else { + // err - tried to use an invalid alias + $msg = __( 'Could not add alias (unavailable or invalid):', 'zero-bs-crm' ) . ' ' . $alias; + $zbs->DAL->addError( 307, $this->objectType, $msg, $alias ); - } + } + } + } + } // / if $data/limitedData - // / Custom Fields + // 2.98.1+ ... custom fields should update if present, regardless of limitedData rule + // ... UNLESS BLANK! + // Custom fields? - #} Any extra meta keyval pairs? - // BRUTALLY updates (no checking) - $confirmedExtraMeta = false; - if ( is_array( $extraMeta ) ) { // phpcs:ignore -- PHPCS is choking on this line, so ignoring it altogether...the var is defined at the beginning of the function. + #} Cycle through + add/update if set + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { - $confirmedExtraMeta = array(); + // any? + if ( isset( $data[ $cK ] ) ) { - foreach ($extraMeta as $k => $v){ + // updating blanks? + if ( $do_not_update_blanks && empty( $data[ $cK ] ) ) { - #} This won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + // skip it - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_CONTACT,$newID,'extra_'.$cleanKey,$v); + } else { - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $v; + // it's either not in do_not_update_blank mode, or it has a val - } + // add update + $cfID = $this->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_CONTACT, + '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; - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT + if ( isset( $data[ $cKey ] ) ) { - // zbs_write_log("ABOUT TO HIT THE AUTOMATOR... " . $silentInsert); + // updating blanks? + if ( $do_not_update_blanks && empty( $data[ $cKey ] ) ) { - if (!$silentInsert){ + // skip it - //zbs_write_log("HITTING IT NOW..."); + } else { - #} Add to automator - zeroBSCRM_FireInternalAutomator('contact.new',array( - 'id'=>$newID, - 'customerMeta'=>$dataArr, - 'extsource'=>$approvedExternalSource, - 'automatorpassthrough'=>$automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. - 'customerExtraMeta'=>$confirmedExtraMeta #} This is the "extraMeta" passed (as saved) - )); + // it's either not in do_not_update_blank mode, or it has a val - $dataArr['ID'] = $newID; // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect - $this->events_manager->contact()->created( $dataArr ); // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect + // add update + $cfID = $this->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $id, + 'objkey' => $cKey, + 'objval' => $data[ $cKey ], + ), + ) + ); - } - - return $newID; + } + } - } else { - - $msg = __('DB Insert Failed','zero-bs-crm'); - $zbs->DAL->addError(303,$this->objectType,$msg,$dataArr); - // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // any? + if ( isset( $data[ $cKey2 ] ) ) { - #} Failed to Insert - return false; + // updating blanks? + if ( $do_not_update_blanks && empty( $data[ $cKey2 ] ) ) { - } + // skip it - } + } else { - return false; + // it's either not in do_not_update_blank mode, or it has a val - } + // add update + $cfID = $this->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $id, + 'objkey' => $cKey2, + 'objval' => $data[ $cKey2 ], + ), + ) + ); - /** - * adds or updates a contact'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 addUpdateContactTags($args=array()){ + } + } + } + } - global $ZBSCRM_t,$wpdb; + // / Custom Fields - #} ============ LOAD ARGS ============= - $defaultArgs = 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 - 'id' => -1, - - // generic pass-through (array of tag strings or tag IDs): - 'tag_input' => -1, + $confirmedExtraMeta = array(); - // or either specific: - 'tagIDs' => -1, - 'tags' => -1, + foreach ( $extraMeta as $k => $v ) { - 'mode' => 'append' + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - ); 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 ============ + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_CONTACT, $id, 'extra_' . $cleanKey, $v ); - #} ========== CHECK FIELDS ============ + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; + } + } - #} ========= / CHECK 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 + ) { + + #} Brutal add, maybe validate more?! + + #} Long desc if present: + $zbsNoteLongDesc = ''; + if ( isset( $fallBackLog['longdesc'] ) && ! empty( $fallBackLog['longdesc'] ) ) { + $zbsNoteLongDesc = $fallBackLog['longdesc']; + } - return $this->DAL()->addUpdateObjectTags( - array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $id, - 'tag_input' => $tag_input, - 'tags' => $tags, - 'tagIDs' => $tagIDs, - 'mode' => $mode - ) - ); + #} Only raw checked... but proceed. + $newOrUpdatedLogID = zeroBS_addUpdateContactLog( + $id, + -1, + -1, + array( + #} Anything here will get wrapped into an array and added as the meta vals + 'type' => $fallBackLog['type'], + 'shortdesc' => $fallBackLog['shortdesc'], + 'longdesc' => $zbsNoteLongDesc, + ) + ); - } + } - /** - * adds or updates a contact's company links - * ... this is really just a wrapper for addUpdateObjLinks - * fill in for zbsCRM_addUpdateCustomerCompany + zeroBS_setCustomerCompanyID - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateContactCompanies($args=array()){ + // catch dirty flag (update of status) (note, after update_post_meta - as separate) + // if (isset($_POST['zbsc_status_dirtyflag']) && $_POST['zbsc_status_dirtyflag'] == "1"){ + // actually here, it's set above + if ( isset( $statusChange ) && is_array( $statusChange ) ) { + + // status has changed + + // IA + zeroBSCRM_FireInternalAutomator( + 'contact.status.update', + array( + 'id' => $id, + 'againstid' => $id, + 'userMeta' => $dataArr, + 'from' => $statusChange['from'], + 'to' => $statusChange['to'], + ) + ); - global $ZBSCRM_t,$wpdb; + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // IA General contact update (2.87+) + zeroBSCRM_FireInternalAutomator( + 'contact.update', + array( + 'id' => $id, + 'againstid' => $id, + 'userMeta' => $dataArr, + 'prevSegments' => $contactsPreUpdateSegments, + 'prev_contact' => $previous_contact_obj, + ) + ); - 'id' => -1, - 'companyIDs' => -1 + $dataArr['id'] = $id; + $this->events_manager->contact()->updated( $dataArr, $previous_contact_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 ============ + // Successfully updated - Return id + return $id; - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; + } else { - // check co id's - if (!is_array($companyIDs)) $companyIDs = array(); + $msg = __( 'DB Update Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 302, $this->objectType, $msg, $dataArr ); - #} ========= / CHECK FIELDS =========== - - return $this->DAL()->addUpdateObjLinks(array( - 'objtypefrom' => ZBS_TYPE_CONTACT, - 'objtypeto' => ZBS_TYPE_COMPANY, - 'objfromid' => $id, - 'objtoids' => $companyIDs)); + // FAILED update + return false; - } + } + } else { + + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['contacts'], + $dataArr, + $typeArr + ) > 0 ) { + + #} Successfully inserted, lets return new ID + $newID = $wpdb->insert_id; + + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { + + $this->addUpdateContactTags( + array( + 'id' => $newID, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); - /** - * adds or updates a contact's WPID - * ... this is really just a wrapper for addUpdateContact - * ... and replaces zeroBS_setCustomerWPID - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateContactWPID($args=array()){ + } - global $ZBSCRM_t,$wpdb; + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $newID, + 'obj_type_id' => ZBS_TYPE_CONTACT, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below + + // co's work? + // OBJ LINKS - to companies (1liner now as genericified) + $this->addUpdateObjectLinks( $newID, $data['companies'], ZBS_TYPE_COMPANY ); + /* + if ( isset( $data['companies']) && is_array( $data['companies']) && count( $data['companies']) > 0) + $this->DAL()->addUpdateObjLinks(array( + 'objtypefrom' => ZBS_TYPE_CONTACT, + 'objtypeto' => ZBS_TYPE_COMPANY, + 'objfromid' => $newID, + 'objtoids' => $data['companies'])); + */ + + // Aliases + // Maintain an array of AKA emails + if ( isset( $data['aliases'] ) && is_array( $data['aliases'] ) ) { + + $existingAliasesSimple = array(); + $existingAliases = zeroBS_getObjAliases( ZBS_TYPE_CONTACT, $newID ); + if ( ! is_array( $existingAliases ) ) { + $existingAliases = array(); + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + // compare + if ( is_array( $existingAliases ) ) { + foreach ( $existingAliases as $alias ) { - 'id' => -1, - 'WPID' => -1 + // is this alias in the new list? + if ( in_array( $alias['aka_alias'], $data['aliases'] ) ) { + $existingAliasesSimple[] = $alias['aka_alias']; + continue; + } - ); 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 ============ + // it's not in the new list, thus, remove it: + // this could be a smidgen more performant if it just deleted the line + zeroBS_removeObjAlias( ZBS_TYPE_CONTACT, $newID, $alias['aka_alias'] ); - #} ========== CHECK FIELDS ============ + } + } + foreach ( $data['aliases'] as $alias ) { - // check id - $id = (int)$id; if (empty($id) || $id <= 0) return false; + // valid? + if ( zeroBS_canUseCustomerAlias( $alias ) ) { - // WPID may be -1 (NULL) - // -1 does okay here if ($WPID == -1) $WPID = ''; + // is this alias in the existing list? (nothing to do) + if ( in_array( $alias, $existingAliasesSimple ) ) { + continue; + } - #} ========= / CHECK FIELDS =========== + // it's not in the existing list, thus, add it: + zeroBS_addObjAlias( ZBS_TYPE_CONTACT, $newID, $alias ); + } else { - #} Enact - return $this->addUpdateContact(array( - 'id' => $id, - 'limitedFields' =>array( - array('key'=>'zbsc_wpid','val'=>$WPID,'type'=>'%d') - ))); + // err - tried to use an invalid alias + $msg = __( 'Could not add alias (unavailable or invalid):', 'zero-bs-crm' ) . ' ' . $alias; + $zbs->DAL->addError( 307, $this->objectType, $msg, $alias ); - + } + } + } - } + // 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_CONTACT, + 'objid' => $newID, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), + ) + ); - /** - * deletes a contact object - * - * @param array $args Associative array of arguments - * id - * - * @return int success; - */ - public function deleteContact($args=array()){ + } + } + } - global $zbs; + // 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; + + if ( isset( $data[ $cKey ] ) ) { + + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $newID, + 'objkey' => $cKey, + 'objval' => $data[ $cKey ], + ), + ) + ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + } - 'id' => -1, - 'saveOrphans' => true + // any? + if ( isset( $data[ $cKey2 ] ) ) { + + // add update + $cfID = $this->DAL()->addUpdateCustomField( + array( + 'data' => array( + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $newID, + 'objkey' => $cKey2, + 'objval' => $data[ $cKey2 ], + ), + ) + ); - ); 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 ============ + } + // phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - #} Before we actually delete - allow a hook and pass the args (which is just the id and whether saveOrphans or not) - zeroBSCRM_FireInternalAutomator('contact.before.delete',array( - 'id'=>$id, - 'saveOrphans'=>$saveOrphans - )); - // phpcs:ignore - $this->events_manager->contact()->before_delete( $id ); + } + } - #} Check ID & Delete :) - $id = (int)$id; - if (!empty($id) && $id > 0) { - - // delete orphans? - if ($saveOrphans === false){ + // / Custom Fields - #DB1LEGACY (TOMOVE -> where) - // delete quotes - $qs = zeroBS_getQuotesForCustomer($id,false,1000000,0,false,false); - foreach ($qs as $q){ + #} Any extra meta keyval pairs? + // BRUTALLY updates (no checking) + $confirmedExtraMeta = false; + if ( is_array( $extraMeta ) ) { // phpcs:ignore -- PHPCS is choking on this line, so ignoring it altogether...the var is defined at the beginning of the function. - // delete post - $zbs->DAL->quotes->deleteQuote( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - array( - 'id' => $q['id'], - 'saveOrphans' => false, - ) - ); + $confirmedExtraMeta = array(); - } unset($qs); + foreach ( $extraMeta as $k => $v ) { - #DB1LEGACY (TOMOVE -> where) - // delete invoices - $is = zeroBS_getInvoicesForCustomer($id,false,1000000,0,false); - foreach ($is as $i){ + #} This won't fix stupid keys, just catch basic fails... + $cleanKey = strtolower( str_replace( ' ', '_', $k ) ); - // delete post - $zbs->DAL->invoices->deleteInvoice( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - array( - 'id' => $i['id'], - 'saveOrphans' => false, - ) - ); + #} Brutal update + // update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); + $this->DAL()->updateMeta( ZBS_TYPE_CONTACT, $newID, 'extra_' . $cleanKey, $v ); - } unset($qs); + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; - #DB1LEGACY (TOMOVE -> where) - // delete transactions - $trans = zeroBS_getTransactionsForCustomer($id,false,1000000,0,false); - foreach ($trans as $tran){ - - // delete post - $zbs->DAL->transactions->deleteTransaction( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - array( - 'id' => $tran['id'], - 'saveOrphans' => false, - ) - ); - - } unset( $trans ); - - // delete events - $events = zeroBS_getEventsByCustomerID( $id, false, 1000000, 0 ); - foreach ( $events as $event ) { - - // delete post - $zbs->DAL->events->deleteEvent( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - array( - 'id' => $event['id'], - 'saveOrphans' => false, - ) - ); - - } unset($events); - - - // delete any tag links - $this->DAL()->deleteTagObjLinks(array( - - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $id - )); - - - // delete any external source information - $this->DAL()->delete_external_sources( array( - - 'obj_type' => ZBS_TYPE_CONTACT, - 'obj_id' => $id, - 'obj_source' => 'all', - - )); - - - } - - // delete any alias information (must delete regardless of - // $saveOrphans because there isn't a place where aliases are - // listed, so they would block forever usage of aliased emails) - $existing_aliases = zeroBS_getObjAliases( ZBS_TYPE_CONTACT, $id ); - if ( is_array( $existing_aliases ) ) { - foreach ( $existing_aliases as $alias ) { - zeroBS_removeObjAlias( ZBS_TYPE_CONTACT, $id, $alias['aka_alias'] ); - } - } - - $del = zeroBSCRM_db2_deleteGeneric($id,'contacts'); - - #} Add to automator - zeroBSCRM_FireInternalAutomator('contact.delete',array( - 'id'=>$id, - 'saveOrphans'=>$saveOrphans - )); - - $this->events_manager->contact()->deleted( $id ); - - return $del; - - } - - return false; - - } - - /** - * tidy's the object from wp db into clean array - * - * @param array $obj (DB obj) - * - * @return array (clean obj) - */ - public function tidy_contact( $obj = false, $withCustomFields = false ) { // phpcs:ignore - - 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['status'] = $this->stripSlashes($obj->zbsc_status); - $res['email'] = $obj->zbsc_email; - $res['prefix'] = $this->stripSlashes($obj->zbsc_prefix); - $res['fname'] = $this->stripSlashes($obj->zbsc_fname); - $res['lname'] = $this->stripSlashes($obj->zbsc_lname); - $res['addr1'] = $this->stripSlashes($obj->zbsc_addr1); - $res['addr2'] = $this->stripSlashes($obj->zbsc_addr2); - $res['city'] = $this->stripSlashes($obj->zbsc_city); - $res['county'] = $this->stripSlashes($obj->zbsc_county); - $res['country'] = $this->stripSlashes($obj->zbsc_country); - $res['postcode'] = $this->stripSlashes($obj->zbsc_postcode); - - // until we add multi-addr support, these get translated into old field names (secaddr_) - $res['secaddr_addr1'] = $this->stripSlashes($obj->zbsc_secaddr1); - $res['secaddr_addr2'] = $this->stripSlashes($obj->zbsc_secaddr2); - $res['secaddr_city'] = $this->stripSlashes($obj->zbsc_seccity); - $res['secaddr_county'] = $this->stripSlashes($obj->zbsc_seccounty); - $res['secaddr_country'] = $this->stripSlashes($obj->zbsc_seccountry); - $res['secaddr_postcode'] = $this->stripSlashes($obj->zbsc_secpostcode); - $res['hometel'] = $obj->zbsc_hometel; - $res['worktel'] = $obj->zbsc_worktel; - $res['mobtel'] = $obj->zbsc_mobtel; - //$res['notes'] = $obj->zbsc_notes; - $res['worktel'] = $obj->zbsc_worktel; - $res['wpid'] = $obj->zbsc_wpid; - $res['avatar'] = $obj->zbsc_avatar; - $res['tw'] = $obj->zbsc_tw; - $res['li'] = $obj->zbsc_li; - $res['fb'] = $obj->zbsc_fb; - - - // gross backward compat - if ($zbs->db1CompatabilitySupport) $res['meta'] = $res; - - // to maintain old obj more easily, here we refine created into datestamp - $res['created'] = zeroBSCRM_locale_utsToDatetime($obj->zbsc_created); - if ($obj->zbsc_lastcontacted != -1 && !empty($obj->zbsc_lastcontacted) && $obj->zbsc_lastcontacted > 0) - $res['lastcontacted'] = zeroBSCRM_locale_utsToDatetime($obj->zbsc_lastcontacted); - else - $res['lastcontacted'] = -1; - $res['createduts'] = $obj->zbsc_created; // this is the UTS (int14) - - // this is in v3.0+ format. - $res['created_date'] = ( isset( $obj->zbsc_created ) && $obj->zbsc_created > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsc_created ) : false; - $res['lastupdated'] = $obj->zbsc_lastupdated; - $res['lastupdated_date'] = ( isset( $obj->zbsc_lastupdated ) && $obj->zbsc_lastupdated > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsc_lastupdated ) : false; - $res['lastcontacteduts'] = $obj->zbsc_lastcontacted; // this is the UTS (int14) - $res['lastcontacted_date'] = ( isset( $obj->zbsc_lastcontacted ) && $obj->zbsc_lastcontacted > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsc_lastcontacted ) : false; - - // latest logs - if (isset($obj->lastlog)) $res['lastlog'] = $obj->lastlog; - if (isset($obj->lastcontactlog)) $res['lastcontactlog'] = $obj->lastcontactlog; - - // Build any extra formats (using fields) - $res['fullname'] = $this->format_fullname($res); - $res['name'] = $res['fullname']; // this one is for backward compat (pre db2) - - // 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; - // 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_CONTACT,$obj,$res,true); + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // NEW CONTACT + + // zbs_write_log("ABOUT TO HIT THE AUTOMATOR... " . $silentInsert); - // Aliases - if (isset($obj->aliases) && is_string($obj->aliases) && !empty($obj->aliases)){ + if ( ! $silentInsert ) { - // csv => array - $res['aliases'] = explode(',',$obj->aliases); + // zbs_write_log("HITTING IT NOW..."); - } + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'contact.new', + array( + 'id' => $newID, + 'customerMeta' => $dataArr, + 'extsource' => $approvedExternalSource, + 'automatorpassthrough' => $automatorPassthrough, #} This passes through any custom log titles or whatever into the Internal automator recipe. + 'customerExtraMeta' => $confirmedExtraMeta, #} This is the "extraMeta" passed (as saved) + ) + ); - } + $dataArr['ID'] = $newID; + $this->events_manager->contact()->created( $dataArr ); - return $res; + } + return $newID; - } + } else { + $msg = __( 'DB Insert Failed', 'zero-bs-crm' ); + $zbs->DAL->addError( 303, $this->objectType, $msg, $dataArr ); + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - /** - * 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) - */ - private function db_ready_contact($obj=false){ + #} Failed to Insert + return false; - global $zbs; + } + } - /* - if (is_array($obj)){ + return false; + } - $removeNonDBFields = array('meta','fullname','name'); + /** + * adds or updates a contact'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 addUpdateContactTags( $args = array() ) { - foreach ($removeNonDBFields as $fKey){ + global $ZBSCRM_t, $wpdb; - if (isset($obj[$fKey])) unset($obj[$fKey]); + #} ============ LOAD ARGS ============= + $defaultArgs = array( - } + 'id' => -1, - } - */ + // generic pass-through (array of tag strings or tag IDs): + 'tag_input' => -1, - $legitFields = array( - 'owner','status','email','prefix','fname','lname', - 'addr1','addr2','city','county','country','postcode', - // WH corrected 13/06/18 2.84 'secaddr_addr1','secaddr_addr2','secaddr_city','secaddr_county','secaddr_country','secaddr_postcode', - 'secaddr1','secaddr2','seccity','seccounty','seccountry','secpostcode', - 'hometel','worktel','mobtel', - 'wpid','avatar', - 'tw','fb','li', - 'created','lastupdated','lastcontacted'); + // or either specific: + 'tagIDs' => -1, + 'tags' => -1, + 'mode' => 'append', - $ret = array(); - if (is_array($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 ($legitFields as $fKey){ + #} ========== CHECK FIELDS ============ - if (isset($obj[$fKey])) $ret[$fKey] = $obj[$fKey]; + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } - } + #} ========= / CHECK FIELDS =========== + + return $this->DAL()->addUpdateObjectTags( + array( + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $id, + 'tag_input' => $tag_input, + 'tags' => $tags, + 'tagIDs' => $tagIDs, + 'mode' => $mode, + ) + ); + } + + /** + * adds or updates a contact's company links + * ... this is really just a wrapper for addUpdateObjLinks + * fill in for zbsCRM_addUpdateCustomerCompany + zeroBS_setCustomerCompanyID + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateContactCompanies( $args = array() ) { + + global $ZBSCRM_t, $wpdb; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'companyIDs' => -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 ============ - return $ret; + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } + // check co id's + if ( ! is_array( $companyIDs ) ) { + $companyIDs = array(); + } - } + #} ========= / CHECK FIELDS =========== + + return $this->DAL()->addUpdateObjLinks( + array( + 'objtypefrom' => ZBS_TYPE_CONTACT, + 'objtypeto' => ZBS_TYPE_COMPANY, + 'objfromid' => $id, + 'objtoids' => $companyIDs, + ) + ); + } + + /** + * adds or updates a contact's WPID + * ... this is really just a wrapper for addUpdateContact + * ... and replaces zeroBS_setCustomerWPID + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateContactWPID( $args = array() ) { + + global $ZBSCRM_t, $wpdb; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'id' => -1, + 'WPID' => -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 ============ - /** - * Wrapper, use $this->getContactMeta($contactID,$key) for easy retrieval of singular - * Simplifies $this->getMeta - * - * @param int objtype - * @param int objid - * @param string key - * - * @return bool result - */ - public function getContactMeta($id=-1,$key='',$default=false){ + #} ========== CHECK FIELDS ============ - global $zbs; + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } - if (!empty($key)){ + // WPID may be -1 (NULL) + // -1 does okay here if ($WPID == -1) $WPID = ''; + + #} ========= / CHECK FIELDS =========== + + #} Enact + return $this->addUpdateContact( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsc_wpid', + 'val' => $WPID, + 'type' => '%d', + ), + ), + ) + ); + } + + /** + * deletes a contact object + * + * @param array $args Associative array of arguments + * id + * + * @return int success; + */ + public function deleteContact( $args = array() ) { + + global $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 ============ + + #} Before we actually delete - allow a hook and pass the args (which is just the id and whether saveOrphans or not) + zeroBSCRM_FireInternalAutomator( + 'contact.before.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); + // phpcs:ignore + $this->events_manager->contact()->before_delete( $id ); + + #} Check ID & Delete :) + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + + // delete orphans? + if ( $saveOrphans === false ) { + + #DB1LEGACY (TOMOVE -> where) + // delete quotes + $qs = zeroBS_getQuotesForCustomer( $id, false, 1000000, 0, false, false ); + foreach ( $qs as $q ) { + + // delete post + $zbs->DAL->quotes->deleteQuote( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + array( + 'id' => $q['id'], + 'saveOrphans' => false, + ) + ); - return $this->DAL()->getMeta(array( + } + unset( $qs ); + + #DB1LEGACY (TOMOVE -> where) + // delete invoices + $is = zeroBS_getInvoicesForCustomer( $id, false, 1000000, 0, false ); + foreach ( $is as $i ) { + + // delete post + $zbs->DAL->invoices->deleteInvoice( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + array( + 'id' => $i['id'], + 'saveOrphans' => false, + ) + ); - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $id, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default, - 'ignoreowner' => true // for now !! + } + unset( $qs ); + + #DB1LEGACY (TOMOVE -> where) + // delete transactions + $trans = zeroBS_getTransactionsForCustomer( $id, false, 1000000, 0, false ); + foreach ( $trans as $tran ) { + + // delete post + $zbs->DAL->transactions->deleteTransaction( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + array( + 'id' => $tran['id'], + 'saveOrphans' => false, + ) + ); - )); + } + unset( $trans ); + + // delete events + $events = zeroBS_getEventsByCustomerID( $id, false, 1000000, 0 ); + foreach ( $events as $event ) { + + // delete post + $zbs->DAL->events->deleteEvent( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + array( + 'id' => $event['id'], + 'saveOrphans' => false, + ) + ); - } + } + unset( $events ); - return $default; - } + // delete any tag links + $this->DAL()->deleteTagObjLinks( + array( - /** - * returns external source detail lines for a contact - * - * @param array $args Associative array of arguments - * withStats, searchPhrase, sortByField, sortOrder, page, perPage - * - * @return array of tag lines - */ - public function getExternalSourcesForContact($args=array()){ + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $id, + ) + ); - global $zbs; + // delete any external source information + $this->DAL()->delete_external_sources( + array( - #} ============ LOAD ARGS ============= - $defaultArgs = array( + 'obj_type' => ZBS_TYPE_CONTACT, + 'obj_id' => $id, + 'obj_source' => 'all', - 'contactID' => -1, + ) + ); - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, - 'perPage' => 100, + } - // permissions - 'ignoreowner' => false // this'll let you not-check the owner of obj + // delete any alias information (must delete regardless of + // $saveOrphans because there isn't a place where aliases are + // listed, so they would block forever usage of aliased emails) + $existing_aliases = zeroBS_getObjAliases( ZBS_TYPE_CONTACT, $id ); + if ( is_array( $existing_aliases ) ) { + foreach ( $existing_aliases as $alias ) { + zeroBS_removeObjAlias( ZBS_TYPE_CONTACT, $id, $alias['aka_alias'] ); + } + } - ); 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 ============= + $del = zeroBSCRM_db2_deleteGeneric( $id, 'contacts' ); - #} ========== CHECK FIELDS ============ + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'contact.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); - $contactID = (int)$contactID; - - #} ========= / CHECK FIELDS =========== + $this->events_manager->contact()->deleted( $id ); - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + return $del; - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['externalsources']; + } - #} ============= WHERE ================ + return false; + } + + /** + * tidy's the object from wp db into clean array + * + * @param array $obj (DB obj) + * + * @return array (clean obj) + */ + public function tidy_contact( $obj = false, $withCustomFields = false ) { // phpcs:ignore + + 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['status'] = $this->stripSlashes( $obj->zbsc_status ); + $res['email'] = $obj->zbsc_email; + $res['prefix'] = $this->stripSlashes( $obj->zbsc_prefix ); + $res['fname'] = $this->stripSlashes( $obj->zbsc_fname ); + $res['lname'] = $this->stripSlashes( $obj->zbsc_lname ); + $res['addr1'] = $this->stripSlashes( $obj->zbsc_addr1 ); + $res['addr2'] = $this->stripSlashes( $obj->zbsc_addr2 ); + $res['city'] = $this->stripSlashes( $obj->zbsc_city ); + $res['county'] = $this->stripSlashes( $obj->zbsc_county ); + $res['country'] = $this->stripSlashes( $obj->zbsc_country ); + $res['postcode'] = $this->stripSlashes( $obj->zbsc_postcode ); + + // until we add multi-addr support, these get translated into old field names (secaddr_) + $res['secaddr_addr1'] = $this->stripSlashes( $obj->zbsc_secaddr1 ); + $res['secaddr_addr2'] = $this->stripSlashes( $obj->zbsc_secaddr2 ); + $res['secaddr_city'] = $this->stripSlashes( $obj->zbsc_seccity ); + $res['secaddr_county'] = $this->stripSlashes( $obj->zbsc_seccounty ); + $res['secaddr_country'] = $this->stripSlashes( $obj->zbsc_seccountry ); + $res['secaddr_postcode'] = $this->stripSlashes( $obj->zbsc_secpostcode ); + $res['hometel'] = $obj->zbsc_hometel; + $res['worktel'] = $obj->zbsc_worktel; + $res['mobtel'] = $obj->zbsc_mobtel; + // $res['notes'] = $obj->zbsc_notes; + $res['worktel'] = $obj->zbsc_worktel; + $res['wpid'] = $obj->zbsc_wpid; + $res['avatar'] = $obj->zbsc_avatar; + $res['tw'] = $obj->zbsc_tw; + $res['li'] = $obj->zbsc_li; + $res['fb'] = $obj->zbsc_fb; + + // gross backward compat + if ( $zbs->db1CompatabilitySupport ) { + $res['meta'] = $res; + } - #} contactID - if (!empty($contactID) && $contactID > 0) $wheres['zbss_objid'] = array('zbss_objid','=','%d',$contactID); - - // type - $wheres['zbss_objtype'] = array('zbss_objtype','=','%d',1); + // to maintain old obj more easily, here we refine created into datestamp + $res['created'] = zeroBSCRM_locale_utsToDatetime( $obj->zbsc_created ); + if ( $obj->zbsc_lastcontacted != -1 && ! empty( $obj->zbsc_lastcontacted ) && $obj->zbsc_lastcontacted > 0 ) { + $res['lastcontacted'] = zeroBSCRM_locale_utsToDatetime( $obj->zbsc_lastcontacted ); + } else { + $res['lastcontacted'] = -1; + } + $res['createduts'] = $obj->zbsc_created; // this is the UTS (int14) + + // this is in v3.0+ format. + $res['created_date'] = ( isset( $obj->zbsc_created ) && $obj->zbsc_created > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsc_created ) : false; + $res['lastupdated'] = $obj->zbsc_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbsc_lastupdated ) && $obj->zbsc_lastupdated > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsc_lastupdated ) : false; + $res['lastcontacteduts'] = $obj->zbsc_lastcontacted; // this is the UTS (int14) + $res['lastcontacted_date'] = ( isset( $obj->zbsc_lastcontacted ) && $obj->zbsc_lastcontacted > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsc_lastcontacted ) : false; + + // latest logs + if ( isset( $obj->lastlog ) ) { + $res['lastlog'] = $obj->lastlog; + } + if ( isset( $obj->lastcontactlog ) ) { + $res['lastcontactlog'] = $obj->lastcontactlog; + } + // Build any extra formats (using fields) + $res['fullname'] = $this->format_fullname( $res ); + $res['name'] = $res['fullname']; // this one is for backward compat (pre db2) - #} ============ / WHERE =============== + // 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; + } - #} Build out any WHERE clauses - $wheresArr= $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + // 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 ); + } - #} 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 fields - tidy any that are present: + if ( $withCustomFields ) { + $res = $this->tidyAddCustomFields( ZBS_TYPE_CONTACT, $obj, $res, true ); + } - #} Append to sql (this also automatically deals with sortby and paging) - $query .= $this->buildWhereStr($whereStr,$additionalWhere) . $this->buildSort($sortByField,$sortOrder) . $this->buildPaging($page,$perPage); + // Aliases + if ( isset( $obj->aliases ) && is_string( $obj->aliases ) && ! empty( $obj->aliases ) ) { - try { + // csv => array + $res['aliases'] = explode( ',', $obj->aliases ); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + } + } - } catch (Exception $e){ + return $res; + } - #} General SQL Err - $this->catchSQLError($e); + /** + * 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) + */ + private function db_ready_contact( $obj = false ) { - } + global $zbs; - #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + /* + if ( is_array( $obj)){ - #} Has results, tidy + return - foreach ($potentialRes as $resDataLine) { - - // tidy - $resArr = $this->DAL()->tidy_externalsource($resDataLine); + $removeNonDBFields = array('meta','fullname','name'); - $res[] = $resArr; + foreach ( $removeNonDBFields as $fKey){ - } - } + if ( isset( $obj[$fKey])) unset( $obj[$fKey]); - return $res; - } + } - - /** - * returns tracking detail lines for a contact - * - * @param array $args Associative array of arguments - * withStats, searchPhrase, sortByField, sortOrder, page, perPage - * - * @return array of tag lines - */ - public function getTrackingForContact($args=array()){ + } + */ + + $legitFields = array( + 'owner', + 'status', + 'email', + 'prefix', + 'fname', + 'lname', + 'addr1', + 'addr2', + 'city', + 'county', + 'country', + 'postcode', + // WH corrected 13/06/18 2.84 'secaddr_addr1','secaddr_addr2','secaddr_city','secaddr_county','secaddr_country','secaddr_postcode', + 'secaddr1', + 'secaddr2', + 'seccity', + 'seccounty', + 'seccountry', + 'secpostcode', + 'hometel', + 'worktel', + 'mobtel', + 'wpid', + 'avatar', + 'tw', + 'fb', + 'li', + 'created', + 'lastupdated', + 'lastcontacted', + ); + + $ret = array(); + if ( is_array( $obj ) ) { + + foreach ( $legitFields as $fKey ) { + + if ( isset( $obj[ $fKey ] ) ) { + $ret[ $fKey ] = $obj[ $fKey ]; + } + } + } - global $zbs; + return $ret; + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + /** + * Wrapper, use $this->getContactMeta($contactID,$key) for easy retrieval of singular + * Simplifies $this->getMeta + * + * @param int objtype + * @param int objid + * @param string key + * + * @return bool result + */ + public function getContactMeta( $id = -1, $key = '', $default = false ) { - 'contactID' => -1, + global $zbs; - // optional - 'action' => '', + if ( ! empty( $key ) ) { - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, - 'perPage' => 100, + return $this->DAL()->getMeta( + array( - // permissions - 'ignoreowner' => false // this'll let you not-check the owner of obj + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $id, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, + 'ignoreowner' => true, // 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 ============= + ) + ); - #} ========== CHECK FIELDS ============ + } - $contactID = (int)$contactID; - - #} ========= / CHECK FIELDS =========== + return $default; + } + + /** + * returns external source detail lines for a contact + * + * @param array $args Associative array of arguments + * withStats, searchPhrase, sortByField, sortOrder, page, perPage + * + * @return array of tag lines + */ + public function getExternalSourcesForContact( $args = array() ) { + + global $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'contactID' => -1, + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, + 'perPage' => 100, + + // 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 ============= - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); + #} ========== CHECK FIELDS ============ - #} Build query - $query = "SELECT * FROM ".$ZBSCRM_t['tracking']; + $contactID = (int) $contactID; - #} ============= WHERE ================ + #} ========= / CHECK FIELDS =========== - #} contactID - if (!empty($contactID) && $contactID > 0) $wheres['zbst_contactid'] = array('zbst_contactid','=','%d',$contactID); + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - #} action - if (!empty($action)) $wheres['zbst_action'] = array('zbst_action','=','%s',$action); + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['externalsources']; - #} ============ / WHERE =============== + #} ============= WHERE ================ - #} Build out any WHERE clauses - $wheresArr= $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + #} contactID + if ( ! empty( $contactID ) && $contactID > 0 ) { + $wheres['zbss_objid'] = array( 'zbss_objid', '=', '%d', $contactID ); + } - #} 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 + // type + $wheres['zbss_objtype'] = array( 'zbss_objtype', '=', '%d', 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); + #} ============ / 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); - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + #} 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( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - #} 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) { - - // tidy - $resArr = $this->DAL()->tidy_tracking($resDataLine); + #} General SQL Err + $this->catchSQLError( $e ); - $res[] = $resArr; + } - } - } + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - return $res; - } + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - /** - * Returns an ownerid against a contact - * - * @param int id Contact ID - * - * @return int contact owner id - */ - public function getContactOwner($id=-1){ + // tidy + $resArr = $this->DAL()->tidy_externalsource( $resDataLine ); - global $zbs; + $res[] = $resArr; - $id = (int)$id; + } + } - if ($id > 0){ + return $res; + } + + /** + * returns tracking detail lines for a contact + * + * @param array $args Associative array of arguments + * withStats, searchPhrase, sortByField, sortOrder, page, perPage + * + * @return array of tag lines + */ + public function getTrackingForContact( $args = array() ) { + + global $zbs; + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + 'contactID' => -1, + + // optional + 'action' => '', + + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, + 'perPage' => 100, + + // 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 ============= - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); + #} ========== CHECK FIELDS ============ - } + $contactID = (int) $contactID; - return false; - - } + #} ========= / CHECK FIELDS =========== - /** - * Returns an status against a contact - * - * @param int $id Contact ID. - * - * @return string contact status string - */ - public function getContactStatus($id=-1){ + global $ZBSCRM_t, $wpdb; + $wheres = array( 'direct' => array() ); + $whereStr = ''; + $additionalWhere = ''; + $params = array(); + $res = array(); - global $zbs; + #} Build query + $query = 'SELECT * FROM ' . $ZBSCRM_t['tracking']; - $id = (int)$id; + #} ============= WHERE ================ - if ($id > 0){ + #} contactID + if ( ! empty( $contactID ) && $contactID > 0 ) { + $wheres['zbst_contactid'] = array( 'zbst_contactid', '=', '%d', $contactID ); + } - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_status', - 'ignoreowner'=>true)); + #} action + if ( ! empty( $action ) ) { + $wheres['zbst_action'] = array( 'zbst_action', '=', '%s', $action ); + } - } + #} ============ / WHERE =============== - return false; - - } + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - /** - * Sets the status of a contact - * - * @param int $id Contact ID. - * @param string $status Contact status. - * - * @return int|false contact ID if successful, false otherwise - */ - public function setContactStatus( $id=-1, $status=-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 - global $zbs; + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); - $id = (int)$id; + try { - if ($id > 0 && !empty($status) && $status !== -1){ + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - return $this->addUpdateContact(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbsc_status','val' => $status,'type' => '%s') - ))); + } catch ( Exception $e ) { - } + #} General SQL Err + $this->catchSQLError( $e ); - return false; - - } + } - /** - * Sets the owner of a contact - * - * @param int id Contact ID - * @param int owner Contact owner - * - * @return int changed - */ - public function setContactOwner( $id=-1, $owner=-1 ){ + #} Interpret results (Result Set - multi-row) + if ( isset( $potentialRes ) && is_array( $potentialRes ) && count( $potentialRes ) > 0 ) { - global $zbs; + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - $id = (int)$id; - $owner = (int)$owner; + // tidy + $resArr = $this->DAL()->tidy_tracking( $resDataLine ); - if ( $id > 0 && $owner > 0 ){ + $res[] = $resArr; - return $this->addUpdateContact(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbs_owner','val' => $owner,'type' => '%d') - ))); + } + } - } + return $res; + } - return false; - - } + /** + * Returns an ownerid against a contact + * + * @param int id Contact ID + * + * @return int contact owner id + */ + public function getContactOwner( $id = -1 ) { - /** - * Returns an email addr against a contact - * Replaces getContactEmail - * - * @param int id Contact ID - * - * @return string Contact email - */ - public function getContactEmail($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_CONTACT, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_email', - 'ignoreowner' => true)); + } - } + return false; + } - return false; - - } + /** + * Returns an status against a contact + * + * @param int $id Contact ID. + * + * @return string contact status string + */ + public function getContactStatus( $id = -1 ) { - /** - * Updates an email address against a contact - * - * @param int id Contact ID - * @param string $email_address - * - * @return bool success - */ - public function update_contact_email( $id, $email_address ){ + global $zbs; - global $zbs; + $id = (int) $id; - $id = (int)$id; + if ( $id > 0 ) { - if ( $id > 0 && zeroBSCRM_validateEmail( $email_address ) ){ + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_status', + 'ignoreowner' => true, + ) + ); - $this->DAL()->addUpdateContact( array( - 'id' => $id, - 'limitedFields' => array( - array( - 'key' => 'zbsc_email', - 'val' => $email_address, - 'type' => '%s' - ) - ) - )); + } - return true; + return false; + } + + /** + * Sets the status of a contact + * + * @param int $id Contact ID. + * @param string $status Contact status. + * + * @return int|false contact ID if successful, false otherwise + */ + public function setContactStatus( $id = -1, $status = -1 ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 && ! empty( $status ) && $status !== -1 ) { + + return $this->addUpdateContact( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsc_status', + 'val' => $status, + 'type' => '%s', + ), + ), + ) + ); - } + } - return false; - - } + return false; + } + + /** + * Sets the owner of a contact + * + * @param int id Contact ID + * @param int owner Contact owner + * + * @return int changed + */ + public function setContactOwner( $id = -1, $owner = -1 ) { + + global $zbs; + + $id = (int) $id; + $owner = (int) $owner; + + if ( $id > 0 && $owner > 0 ) { + + return $this->addUpdateContact( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbs_owner', + 'val' => $owner, + 'type' => '%d', + ), + ), + ) + ); + } + return false; + } + /** + * Returns an email addr against a contact + * Replaces getContactEmail + * + * @param int id Contact ID + * + * @return string Contact email + */ + public function getContactEmail( $id = -1 ) { - /** - * Returns all email addrs against a contact - * ... including aliases - * - * @param int id Contact ID - * - * @return array of strings (Contact emails) - */ - public function getContactEmails($id=-1){ + global $zbs; - global $zbs; + $id = (int) $id; - $id = (int)$id; - $emails = array(); + if ( $id > 0 ) { - if ($id > 0){ + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_email', + 'ignoreowner' => true, + ) + ); - // main record - $mainEmail = $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_email', - 'ignoreowner' => true)); + } - if (zeroBSCRM_validateEmail($mainEmail)) $emails[] = $mainEmail; + return false; + } + + /** + * Updates an email address against a contact + * + * @param int id Contact ID + * @param string $email_address + * + * @return bool success + */ + public function update_contact_email( $id, $email_address ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 && zeroBSCRM_validateEmail( $email_address ) ) { + + $this->DAL()->addUpdateContact( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsc_email', + 'val' => $email_address, + 'type' => '%s', + ), + ), + ) + ); - // aliases - $aliases = zeroBS_getObjAliases(ZBS_TYPE_CONTACT,$id); - if (is_array($aliases)) foreach ($aliases as $alias) if (!in_array($alias['aka_alias'],$emails)) $emails[] = $alias['aka_alias']; + return true; + } - } + return false; + } + + /** + * Returns all email addrs against a contact + * ... including aliases + * + * @param int id Contact ID + * + * @return array of strings (Contact emails) + */ + public function getContactEmails( $id = -1 ) { + + global $zbs; + + $id = (int) $id; + $emails = array(); + + if ( $id > 0 ) { + + // main record + $mainEmail = $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_email', + 'ignoreowner' => true, + ) + ); - return $emails; - - } + if ( zeroBSCRM_validateEmail( $mainEmail ) ) { + $emails[] = $mainEmail; + } - /** - * Returns an email addr against a contact - * Replaces zeroBS_customerMobile - * - * @param int id Contact ID - * - * @return string Contact email - */ - public function getContactMobile($id=-1){ + // aliases + $aliases = zeroBS_getObjAliases( ZBS_TYPE_CONTACT, $id ); + if ( is_array( $aliases ) ) { + foreach ( $aliases as $alias ) { + if ( ! in_array( $alias['aka_alias'], $emails ) ) { + $emails[] = $alias['aka_alias']; + } + } + } + } - global $zbs; + return $emails; + } - $id = (int)$id; + /** + * Returns an email addr against a contact + * Replaces zeroBS_customerMobile + * + * @param int id Contact ID + * + * @return string Contact email + */ + public function getContactMobile( $id = -1 ) { - if ($id > 0){ + global $zbs; - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_mobtel', - 'ignoreowner' => true)); + $id = (int) $id; - } + if ( $id > 0 ) { - return false; - - } + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_mobtel', + 'ignoreowner' => true, + ) + ); - /** - * Returns a formatted fullname of a - * Replaces zeroBS_customerName - * - * @param int id Contact ID - * @param array Contact array (if already loaded can pass) - * @param array args (see format_fullname func) - * - * @return string Contact full name - */ - public function getContactFullName($id=-1,$contactArr=false){ + } - global $zbs; + return false; + } + + /** + * Returns a formatted fullname of a + * Replaces zeroBS_customerName + * + * @param int id Contact ID + * @param array Contact array (if already loaded can pass) + * @param array args (see format_fullname func) + * + * @return string Contact full name + */ + public function getContactFullName( $id = -1, $contactArr = false ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 ) { + + // get a limited-fields contact obj + $contact = $this->getContact( + $id, + array( + 'withCustomFields' => false, + 'fields' => array( 'zbsc_prefix', 'zbsc_fname', 'zbsc_lname' ), + 'ignoreowner' => true, + ) + ); + if ( isset( $contact ) && is_array( $contact ) && isset( $contact['prefix'] ) ) { + return $this->format_fullname( $contact ); + } + } elseif ( is_array( $contactArr ) ) { - $id = (int)$id; + // pass through + return $this->format_fullname( $contactArr ); - if ($id > 0){ + } - // get a limited-fields contact obj - $contact = $this->getContact($id,array('withCustomFields' => false,'fields'=>array('zbsc_prefix','zbsc_fname','zbsc_lname'),'ignoreowner' => true)); - if (isset($contact) && is_array($contact) && isset($contact['prefix'])) - return $this->format_fullname($contact); + return false; + } + + /** + * Returns a formatted fullname (optionally including ID + first line of addr) + * Replaces zeroBS_customerName more fully than getContactFullName + * Also replaces zeroBS_getCustomerName + * + * @param int id Contact ID + * @param array Contact array (if already loaded can pass) + * @param array args (see format_fullname func) + * + * @return string Contact full name + */ + public function getContactFullNameEtc( $id = -1, $contactArr = false, $args = array() ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 ) { + + // get a limited-fields contact obj + $contact = $this->getContact( + $id, + array( + 'withCustomFields' => false, + 'fields' => array( 'zbsc_addr1', 'zbsc_prefix', 'zbsc_fname', 'zbsc_lname' ), + 'ignoreowner' => true, + ) + ); + if ( isset( $contact ) && is_array( $contact ) && isset( $contact['prefix'] ) ) { + return $this->format_name_etc( $contact, $args ); + } + } elseif ( is_array( $contactArr ) ) { - } elseif (is_array($contactArr)){ + // pass through + return $this->format_name_etc( $contactArr, $args ); - // pass through - return $this->format_fullname($contactArr); + } - } + return false; + } + + /** + * Returns a formatted name (e.g. Dave Davids) or fallback + * If there is no name, return "Contact #" or a provided hard-coded fallback. Optionally return an email if it exists. + * + * @param int $id Contact ID + * @param array $contactArr (if already loaded can pass) + * @param boolean $do_email_fallback + * @param string $hardcoded_fallback + * + * @return string name or fallback + */ + public function getContactNameWithFallback( $id = -1, $contactArr = false, $do_email_fallback = true, $hardcoded_fallback = '' ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 ) { + + // get a limited-fields contact obj + $contact = $this->getContact( + $id, + array( + 'withCustomFields' => false, + 'fields' => array( + 'zbsc_fname', + 'zbsc_lname', + 'zbsc_email', + ), + 'ignoreowner' => true, + ) + ); + if ( isset( $contact ) && is_array( $contact ) ) { + return $this->format_name_with_fallback( $contact, $do_email_fallback, $hardcoded_fallback ); + } + } elseif ( is_array( $contactArr ) ) { - return false; - - } + // pass through + return $this->format_name_with_fallback( $contactArr, $do_email_fallback, $hardcoded_fallback ); - /** - * Returns a formatted fullname (optionally including ID + first line of addr) - * Replaces zeroBS_customerName more fully than getContactFullName - * Also replaces zeroBS_getCustomerName - * - * @param int id Contact ID - * @param array Contact array (if already loaded can pass) - * @param array args (see format_fullname func) - * - * @return string Contact full name - */ - public function getContactFullNameEtc($id=-1,$contactArr=false,$args=array()){ + } - global $zbs; + return false; + } + + /** + * Returns a formatted address of a contact + * Replaces zeroBS_customerAddr + * + * @param int id Contact ID + * @param array Contact array (if already loaded can pass) + * @param array args (see format_address func) + * + * @return string Contact addr html + */ + public function getContactAddress( $id = -1, $contactArr = false, $args = array() ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 ) { + + // get a limited-fields contact obj + // this is hacky, but basically get whole basic contact record for this for now, because + // this doesn't properly get addr custom fields: + // $contact = $this->getContact($id,array('withCustomFields' => false,'fields'=>$this->field_list_address,'ignoreowner'=>true)); + $contact = $this->getContact( + $id, + array( + 'withCustomFields' => true, + 'ignoreowner' => true, + ) + ); + if ( isset( $contact ) && is_array( $contact ) && isset( $contact['addr1'] ) ) { + return $this->format_address( $contact, $args ); + } + } elseif ( is_array( $contactArr ) ) { - $id = (int)$id; + // pass through + return $this->format_address( $contactArr, $args ); - if ($id > 0){ + } - // get a limited-fields contact obj - $contact = $this->getContact($id,array('withCustomFields' => false,'fields'=>array('zbsc_addr1','zbsc_prefix','zbsc_fname','zbsc_lname'),'ignoreowner' => true)); - if (isset($contact) && is_array($contact) && isset($contact['prefix'])) - return $this->format_name_etc($contact,$args); + return false; + } + + /** + * Returns a formatted address of a contact (2nd addr) + * Replaces zeroBS_customerAddr + * + * @param int id Contact ID + * @param array Contact array (if already loaded can pass) + * @param array args (see format_address func) + * + * @return string Contact addr html + */ + public function getContact2ndAddress( $id = -1, $contactArr = false, $args = array() ) { + + global $zbs; + + $id = (int) $id; + + $args['secondaddr'] = true; + + if ( $id > 0 ) { + + // get a limited-fields contact obj + // this is hacky, but basically get whole basic contact record for this for now, because + // this doesn't properly get addr custom fields: + // $contact = $this->getContact($id,array('withCustomFields' => false,'fields'=>$this->field_list_address2,'ignoreowner'=>true)); + $contact = $this->getContact( + $id, + array( + 'withCustomFields' => true, + 'ignoreowner' => true, + ) + ); + if ( isset( $contact ) && is_array( $contact ) && isset( $contact['addr1'] ) ) { + return $this->format_address( $contact, $args ); + } + } elseif ( is_array( $contactArr ) ) { - } elseif (is_array($contactArr)){ - - // pass through - return $this->format_name_etc($contactArr,$args); - - } - - return false; - - } - - /** - * Returns a formatted name (e.g. Dave Davids) or fallback - * If there is no name, return "Contact #" or a provided hard-coded fallback. Optionally return an email if it exists. - * - * @param int $id Contact ID - * @param array $contactArr (if already loaded can pass) - * @param boolean $do_email_fallback - * @param string $hardcoded_fallback - * - * @return string name or fallback - */ - public function getContactNameWithFallback( $id=-1, $contactArr=false, $do_email_fallback=true, $hardcoded_fallback=''){ + // pass through + return $this->format_address( $contactArr, $args ); - global $zbs; + } - $id = (int)$id; + return false; + } - if ($id > 0){ + /** + * Returns a contacts tag array + * Replaces zeroBSCRM_getCustomerTags AND zeroBSCRM_getContactTagsArr + * + * @param int id Contact ID + * + * @return mixed + */ + public function getContactTags( $id = -1 ) { - // get a limited-fields contact obj - $contact = $this->getContact( - $id, - array( - 'withCustomFields' => false, - 'fields'=>array( - 'zbsc_fname', - 'zbsc_lname', - 'zbsc_email', - ), - 'ignoreowner' => true - ) - ); - if ( isset( $contact ) && is_array( $contact ) ) { - return $this->format_name_with_fallback( $contact, $do_email_fallback, $hardcoded_fallback ); - } - - } elseif ( is_array( $contactArr ) ) { - - // pass through - return $this->format_name_with_fallback( $contactArr, $do_email_fallback, $hardcoded_fallback ); + global $zbs; - } + $id = (int) $id; - return false; + if ( $id > 0 ) { - } + return $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_CONTACT, + 'objid' => $id, + ) + ); - /** - * Returns a formatted address of a contact - * Replaces zeroBS_customerAddr - * - * @param int id Contact ID - * @param array Contact array (if already loaded can pass) - * @param array args (see format_address func) - * - * @return string Contact addr html - */ - public function getContactAddress($id=-1,$contactArr=false,$args=array()){ + } - global $zbs; + return false; + } - $id = (int)$id; + /** + * Returns last contacted uts against a contact + * + * @param int id Contact ID + * + * @return int Contact last contacted date as uts (or -1) + */ + public function getContactLastContactUTS( $id = -1 ) { - if ($id > 0){ + global $zbs; - // get a limited-fields contact obj - // this is hacky, but basically get whole basic contact record for this for now, because - // this doesn't properly get addr custom fields: - // $contact = $this->getContact($id,array('withCustomFields' => false,'fields'=>$this->field_list_address,'ignoreowner'=>true)); - $contact = $this->getContact($id,array('withCustomFields' => true,'ignoreowner'=>true)); - if (isset($contact) && is_array($contact) && isset($contact['addr1'])) - return $this->format_address($contact,$args); + $id = (int) $id; - } elseif (is_array($contactArr)){ + if ( $id > 0 ) { - // pass through - return $this->format_address($contactArr,$args); + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_lastcontacted', + 'ignoreowner' => true, + ) + ); - } + } - return false; - - } - - /** - * Returns a formatted address of a contact (2nd addr) - * Replaces zeroBS_customerAddr - * - * @param int id Contact ID - * @param array Contact array (if already loaded can pass) - * @param array args (see format_address func) - * - * @return string Contact addr html - */ - public function getContact2ndAddress($id=-1,$contactArr=false,$args=array()){ - - global $zbs; - - $id = (int)$id; + return false; + } + + /** + * updates lastcontacted date for a contact + * + * @param int id Contact ID + * @param int uts last contacted + * + * @return bool + */ + public function setContactLastContactUTS( $id = -1, $lastContactedUTS = -1 ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 ) { + + return $this->addUpdateContact( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsc_lastcontacted', + 'val' => $lastContactedUTS, + 'type' => '%d', + ), + ), + ) + ); - $args['secondaddr'] = true; - - if ($id > 0){ + } - // get a limited-fields contact obj - // this is hacky, but basically get whole basic contact record for this for now, because - // this doesn't properly get addr custom fields: - // $contact = $this->getContact($id,array('withCustomFields' => false,'fields'=>$this->field_list_address2,'ignoreowner'=>true)); - $contact = $this->getContact($id,array('withCustomFields' => true,'ignoreowner'=>true)); - if (isset($contact) && is_array($contact) && isset($contact['addr1'])) - return $this->format_address($contact,$args); + return false; + } - } elseif (is_array($contactArr)){ + /** + * Returns a set of social accounts for a contact (tw,li,fb) + * + * @param int id Contact ID + * + * @return array social acc's + */ + public function getContactSocials( $id = -1 ) { - // pass through - return $this->format_address($contactArr,$args); + global $zbs; - } + $id = (int) $id; - return false; - - } - - /** - * Returns a contacts tag array - * Replaces zeroBSCRM_getCustomerTags AND zeroBSCRM_getContactTagsArr - * - * @param int id Contact ID - * - * @return mixed - */ - public function getContactTags($id=-1){ + if ( $id > 0 ) { - global $zbs; + // lazy 3 queries, optimise later - $id = (int)$id; + $tw = $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_tw', + 'ignoreowner' => true, + ) + ); - if ($id > 0){ + $li = $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_li', + 'ignoreowner' => true, + ) + ); - return $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_CONTACT,'objid'=>$id)); + $fb = $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_fb', + 'ignoreowner' => true, + ) + ); - } + return array( + 'tw' => $tw, + 'li' => $li, + 'fb' => $fb, + ); - return false; - - } + } + return false; + } - /** - * Returns last contacted uts against a contact - * - * @param int id Contact ID - * - * @return int Contact last contacted date as uts (or -1) - */ - public function getContactLastContactUTS($id=-1){ + /** + * Returns a linked WP ID against a contact + * Replaces zeroBS_getCustomerWPID + * + * @param int id Contact ID + * + * @return int Contact wp id + */ + public function getContactWPID( $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_CONTACT, - 'colname' => 'zbsc_lastcontacted', - 'ignoreowner' => true)); + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_wpid', + 'ignoreowner' => true, + ) + ); - } + } - return false; - - } + return false; + } - /** - * updates lastcontacted date for a contact - * - * @param int id Contact ID - * @param int uts last contacted - * - * @return bool - */ - public function setContactLastContactUTS($id=-1,$lastContactedUTS=-1){ - - global $zbs; + /** + * Returns true/false whether or not user has 'do-not-email' flag (from unsub email link click) + * + * @param int id Contact ID + * + * @return bool + */ + public function getContactDoNotMail( $id = -1 ) { - $id = (int)$id; + global $zbs; - if ($id > 0){ + $id = (int) $id; - return $this->addUpdateContact(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbsc_lastcontacted','val' => $lastContactedUTS,'type' => '%d') - ))); + if ( $id > 0 ) { - } + return $this->DAL()->meta( ZBS_TYPE_CONTACT, $id, 'do-not-email', false ); - return false; - - } - - /** - * Returns a set of social accounts for a contact (tw,li,fb) - * - * @param int id Contact ID - * - * @return array social acc's - */ - public function getContactSocials($id=-1){ + } - global $zbs; + return false; + } + + /** + * updates true/false whether or not user has 'do-not-email' flag (from unsub email link click) + * + * @param int id Contact ID + * @param bool whether or not to set donotmail + * + * @return bool + */ + public function setContactDoNotMail( $id = -1, $doNotMail = true ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 ) { + + if ( $doNotMail ) { + return $this->DAL()->updateMeta( ZBS_TYPE_CONTACT, $id, 'do-not-email', true ); + } else { // remove + return $this->DAL()->deleteMeta( + array( + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $id, + 'key' => 'do-not-email', + ) + ); + } + } - $id = (int)$id; + return false; + } + + /** + * Returns an url to contact avatar (Gravatar if not set?) + * For now just returns the field + * Replaces zeroBS_getCustomerIcoHTML? + * + * @param int id Contact ID + * + * @return int Contact wp id + */ + public function getContactAvatarURL( $id = -1 ) { + + global $zbs; + + $id = (int) $id; + + if ( $id > 0 ) { + + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'zbsc_avatar', + 'ignoreowner' => true, + ) + ); - if ($id > 0){ - - // lazy 3 queries, optimise later - - $tw = $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_tw', - 'ignoreowner' => true)); + } - $li = $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_li', - 'ignoreowner' => true)); + return false; + } - $fb = $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_fb', - 'ignoreowner' => true)); - - return array('tw'=>$tw,'li' => $li, 'fb' => $fb); - - } - - return false; - - } - - /** - * Returns a linked WP ID against a contact - * Replaces zeroBS_getCustomerWPID - * - * @param int id Contact ID - * - * @return int Contact wp id - */ - public function getContactWPID( $id=-1 ){ - - global $zbs; - - $id = (int)$id; - - if ($id > 0){ - - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_wpid', - 'ignoreowner' => true)); - - } - - return false; - - } - - /** - * Returns true/false whether or not user has 'do-not-email' flag (from unsub email link click) - * - * @param int id Contact ID - * - * @return bool - */ - public function getContactDoNotMail($id=-1){ - - global $zbs; - - $id = (int)$id; - - if ($id > 0){ - - return $this->DAL()->meta(ZBS_TYPE_CONTACT,$id,'do-not-email',false); - - } - - return false; - - } - - /** - * updates true/false whether or not user has 'do-not-email' flag (from unsub email link click) - * - * @param int id Contact ID - * @param bool whether or not to set donotmail - * - * @return bool - */ - public function setContactDoNotMail($id=-1,$doNotMail=true){ - - global $zbs; - - $id = (int)$id; + /** + * Returns an url to contact avatar (Gravatar if not set?) + * Or empty if 'show default empty' = false + * + * @param int id Contact ID + * @param bool showPlaceholder does what it says on tin + * + * @return string URL for img + */ + public function getContactAvatar( $id = -1, $showPlaceholder = true ) { - if ($id > 0){ - - if ($doNotMail) - return $this->DAL()->updateMeta(ZBS_TYPE_CONTACT,$id,'do-not-email',true); - else - // remove - return $this->DAL()->deleteMeta(array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $id, - 'key' => 'do-not-email')); - - } - - return false; - - } - - /** - * Returns an url to contact avatar (Gravatar if not set?) - * For now just returns the field - * Replaces zeroBS_getCustomerIcoHTML? - * - * @param int id Contact ID - * - * @return int Contact wp id - */ - public function getContactAvatarURL($id=-1){ - - global $zbs; - - $id = (int)$id; - - if ($id > 0){ - - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'zbsc_avatar', - 'ignoreowner' => true)); - - } + global $zbs; - return false; - - } - - /** - * Returns an url to contact avatar (Gravatar if not set?) - * Or empty if 'show default empty' = false - * - * @param int id Contact ID - * @param bool showPlaceholder does what it says on tin - * - * @return string URL for img - */ - public function getContactAvatar($id=-1,$showPlaceholder=true){ + $id = (int) $id; - global $zbs; + if ( $id > 0 ) { - $id = (int)$id; + $avatarMode = zeroBSCRM_getSetting( 'avatarmode' ); + switch ( $avatarMode ) { - if ($id > 0){ + case 1: // gravitar + $potentialEmail = $this->getContactEmail( $id ); + if ( ! empty( $potentialEmail ) ) { + return zeroBSCRM_getGravatarURLfromEmail( $potentialEmail ); + } - $avatarMode = zeroBSCRM_getSetting('avatarmode'); - switch ($avatarMode){ + // default + return zeroBSCRM_getDefaultContactAvatar(); + break; - case 1: // gravitar - - $potentialEmail = $this->getContactEmail($id); - if (!empty($potentialEmail)) return zeroBSCRM_getGravatarURLfromEmail($potentialEmail); - - // default - return zeroBSCRM_getDefaultContactAvatar(); + case 2: // custom img + $dbURL = $this->getContactAvatarURL( $id ); + if ( ! empty( $dbURL ) ) { + return $dbURL; + } - break; + // default + return zeroBSCRM_getDefaultContactAvatar(); - case 2: // custom img - - $dbURL = $this->getContactAvatarURL($id); - if (!empty($dbURL)) return $dbURL; + break; - // default - return zeroBSCRM_getDefaultContactAvatar(); + case 3: // none + return ''; + break; - break; + } + } - case 3: // none - return ''; - break; - + // fallback + if ( $showPlaceholder ) { + return zeroBSCRM_getDefaultContactAvatar(); + } - } + return false; + } + /** + * Returns html of contact avatar (Gravatar if not set?) + * Or empty if 'show default empty' = false + * + * @param int id Contact ID + * + * @return string HTML + */ + public function getContactAvatarHTML( $id = -1, $size = 100, $extraClasses = '' ) { - } + $id = (int) $id; - // fallback - if ($showPlaceholder) return zeroBSCRM_getDefaultContactAvatar(); + if ( $id > 0 ) { - return false; - - } + $avatarMode = zeroBSCRM_getSetting( 'avatarmode' ); + switch ( $avatarMode ) { - - /** - * Returns html of contact avatar (Gravatar if not set?) - * Or empty if 'show default empty' = false - * - * @param int id Contact ID - * - * @return string HTML - */ - public function getContactAvatarHTML($id=-1,$size=100,$extraClasses=''){ + case 1: // gravitar + $potentialEmail = $this->getContactEmail( $id ); + if ( ! empty( $potentialEmail ) ) { + return ''; + } - $id = (int)$id; + // default + return zeroBSCRM_getDefaultContactAvatarHTML(); - if ($id > 0){ + break; - $avatarMode = zeroBSCRM_getSetting('avatarmode'); - switch ($avatarMode){ + case 2: // custom img + $dbURL = $this->getContactAvatarURL( $id ); + if ( ! empty( $dbURL ) ) { + return ''; + } + // default + return zeroBSCRM_getDefaultContactAvatarHTML(); - case 1: // gravitar - - $potentialEmail = $this->getContactEmail($id); - if (!empty($potentialEmail)) return ''; - - // default - return zeroBSCRM_getDefaultContactAvatarHTML(); + break; - break; + case 3: // none + return ''; + break; - case 2: // custom img - - $dbURL = $this->getContactAvatarURL($id); - if (!empty($dbURL)) return ''; + } + } - // default - return zeroBSCRM_getDefaultContactAvatarHTML(); + return ''; + } + + /** + * Returns a count of contacts (owned) + * Replaces zeroBS_customerCount + * + * @param object $args - DAL args. + * + * @return int count + */ + public function getContactCount( $args = array() ) { + + #} ============ LOAD ARGS ============= + $defaultArgs = array( + + // Search/Filtering (leave as false to ignore) + 'inCompany' => false, // will be an ID if used + '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 ============= - break; + $whereArr = array(); - case 3: // none - return ''; - break; - + // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable, WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( $inCompany ) { + global $ZBSCRM_t; + $whereArr['incompany'] = array( 'ID', 'IN', '(SELECT DISTINCT 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 = %d)', $inCompany ); + } - } + if ( $withStatus !== false && ! empty( $withStatus ) ) { + $whereArr['status'] = array( 'zbsc_status', '=', 'convert(%s using utf8mb4) collate utf8mb4_bin', $withStatus ); + } + // phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable, WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_CONTACT, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); + + return 0; + } + + /** + * Returns a customer's associated company ID's + * Replaces zeroBS_getCustomerCompanyID (via LEGACY func) + * + * @param int id + * + * @return array int id + */ + public function getContactCompanies( $id = -1 ) { + + if ( ! empty( $id ) ) { + + /* + $contact = $this->getContact( + $id, + array( + 'withCompanies' => true, + 'fields' => array( 'ID' ), + ) + ); - } + if ( is_array( $contact ) && isset( $contact['companies'] ) ) { + return $contact['companies']; + } + */ + + // cleaner: + return $this->DAL()->getObjsLinkedToObj( + array( + 'objtypefrom' => ZBS_TYPE_CONTACT, // contact + 'objtypeto' => ZBS_TYPE_COMPANY, // company + 'objfromid' => $id, + 'ignoreowner' => true, + ) + ); - return ''; - - } + } + return array(); + } + /** + * Returns a bool whether contact has a quote linked to them + * NOTE: this only counts objlinks, so if the obj is deleted and they're not tidied, this'll give false positive + * (Shorthand for contactHasObjLink) + * + * @param int contactID + * @param int obj type id + * + * @return bool + */ + public function contactHasQuote( $contactID = -1 ) { + if ( $contactID > 0 ) { - /** - * Returns a count of contacts (owned) - * Replaces zeroBS_customerCount - * - * @param object $args - DAL args. - * - * @return int count - */ - public function getContactCount($args=array()){ + // cleaner: + $c = $this->contactHasObjLink( $contactID, ZBS_TYPE_QUOTE ); - #} ============ LOAD ARGS ============= - $defaultArgs = array( + if ( $c > 0 ) { + return true; + } + } - // Search/Filtering (leave as false to ignore) - 'inCompany' => false, // will be an ID if used - 'withStatus' => false, // will be str if used + return false; + } - // permissions - 'ignoreowner' => true, // this'll let you not-check the owner of obj + /** + * Returns a bool whether contact has a Invoice linked to them + * NOTE: this only counts objlinks, so if the obj is deleted and they're not tidied, this'll give false positive + * (Shorthand for contactHasObjLink) + * + * @param int contactID + * @param int obj type id + * + * @return bool + */ + public function contactHasInvoice( $contactID = -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 ( $contactID > 0 ) { - $whereArr = array(); + // cleaner: + $c = $this->contactHasObjLink( $contactID, ZBS_TYPE_INVOICE ); - // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable, WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ( $inCompany ) { - global $ZBSCRM_t; - $whereArr['incompany'] = array( 'ID', 'IN', '(SELECT DISTINCT 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 = %d)', $inCompany ); + if ( $c > 0 ) { + return true; } + } - if ( $withStatus !== false && ! empty( $withStatus ) ) { - $whereArr['status'] = array( 'zbsc_status', '=', 'convert(%s using utf8mb4) collate utf8mb4_bin', $withStatus ); - } - // phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable, WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + return false; + } - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_CONTACT, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - - - - return 0; - - } - - /** - * Returns a customer's associated company ID's - * Replaces zeroBS_getCustomerCompanyID (via LEGACY func) - * - * @param int id - * - * @return array int id - */ - public function getContactCompanies($id=-1){ - - if (!empty($id)){ - - /* - $contact = $this->getContact($id,array( - 'withCompanies' => true, - 'fields' => array('ID'))); - - if (is_array($contact) && isset($contact['companies'])) return $contact['companies']; - */ - - // cleaner: - return $this->DAL()->getObjsLinkedToObj(array( - 'objtypefrom' => ZBS_TYPE_CONTACT, // contact - 'objtypeto' => ZBS_TYPE_COMPANY, // company - 'objfromid' => $id, - 'ignoreowner' => true)); - - } - - return array(); - - } - - /** - * Returns a bool whether contact has a quote linked to them - * NOTE: this only counts objlinks, so if the obj is deleted and they're not tidied, this'll give false positive - * (Shorthand for contactHasObjLink) - * - * @param int contactID - * @param int obj type id - * - * @return bool - */ - public function contactHasQuote($contactID=-1){ - - if ($contactID > 0){ - - // cleaner: - $c = $this->contactHasObjLink($contactID,ZBS_TYPE_QUOTE); - - if ($c > 0) return true; - - } - - return false; - - } - - /** - * Returns a bool whether contact has a Invoice linked to them - * NOTE: this only counts objlinks, so if the obj is deleted and they're not tidied, this'll give false positive - * (Shorthand for contactHasObjLink) - * - * @param int contactID - * @param int obj type id - * - * @return bool - */ - public function contactHasInvoice($contactID=-1){ + /** + * Returns a bool whether contact has a transaction linked to them + * NOTE: this only counts objlinks, so if the obj is deleted and they're not tidied, this'll give false positive + * (Shorthand for contactHasObjLink) + * + * @param int contactID + * @param int obj type id + * + * @return bool + */ + public function contactHasTransaction( $contactID = -1 ) { - if ($contactID > 0){ + if ( $contactID > 0 ) { - // cleaner: - $c = $this->contactHasObjLink($contactID,ZBS_TYPE_INVOICE); + // cleaner: + $c = $this->contactHasObjLink( $contactID, ZBS_TYPE_TRANSACTION ); - if ($c > 0) return true; + if ( $c > 0 ) { + return true; + } + } - } + return false; + } + + /** + * Returns a bool whether contact has objtype linked to them + * specifically *obj -> THIS (contact) + * NOTE: this only counts objlinks, so if the obj is deleted and they're not tidied, this'll give false positive + * + * @param int id + * @param int obj type id + * + * @return bool + */ + private function contactHasObjLink( $id = -1, $objTypeID = -1 ) { + + if ( $id > 0 && $objTypeID > 0 ) { + + // cleaner: + $c = $this->DAL()->getObjsLinksLinkedToObj( + array( + 'objtypefrom' => $objTypeID, // obj type + 'objtypeto' => ZBS_TYPE_CONTACT, // contact + 'objtoid' => $id, + 'count' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); - return false; - - } + if ( $c > 0 ) { + return true; + } + } - /** - * Returns a bool whether contact has a transaction linked to them - * NOTE: this only counts objlinks, so if the obj is deleted and they're not tidied, this'll give false positive - * (Shorthand for contactHasObjLink) - * - * @param int contactID - * @param int obj type id - * - * @return bool - */ - public function contactHasTransaction($contactID=-1){ + return false; + } - if ($contactID > 0){ + /** + * Returns the next customer ID and the previous customer ID + * Used for the navigation between contacts. + * + * @param int id + * + * @return array int id + */ + public function getContactPrevNext( $id = -1 ) { - // cleaner: - $c = $this->contactHasObjLink($contactID,ZBS_TYPE_TRANSACTION); + global $ZBSCRM_t, $wpdb; - if ($c > 0) return true; + if ( $id > 0 ) { + // then run the queries.. + $nextSQL = $this->prepare( 'SELECT MIN(ID) FROM ' . $ZBSCRM_t['contacts'] . ' WHERE ID > %d', $id ); - } + $res['next'] = $wpdb->get_var( $nextSQL ); - return false; - - } + $prevSQL = $this->prepare( 'SELECT MAX(ID) FROM ' . $ZBSCRM_t['contacts'] . ' WHERE ID < %d', $id ); - /** - * Returns a bool whether contact has objtype linked to them - * specifically *obj -> THIS (contact) - * NOTE: this only counts objlinks, so if the obj is deleted and they're not tidied, this'll give false positive - * - * @param int id - * @param int obj type id - * - * @return bool - */ - private function contactHasObjLink($id=-1,$objTypeID=-1){ + $res['prev'] = $wpdb->get_var( $prevSQL ); - if ($id > 0 && $objTypeID > 0){ + return $res; - // cleaner: - $c = $this->DAL()->getObjsLinksLinkedToObj(array( - 'objtypefrom' => $objTypeID, // obj type - 'objtypeto' => ZBS_TYPE_CONTACT, // contact - 'objtoid' => $id, - 'count' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + } - if ($c > 0) return true; + return 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( $contact = false, $columnsRequired = array() ) { - } - - return false; - - } + if ( is_array( $contact ) && isset( $contact['id'] ) ) { - /** - * Returns the next customer ID and the previous customer ID - * Used for the navigation between contacts. - * - * @param int id - * - * @return array int id - */ - public function getContactPrevNext($id=-1){ + global $zbs; - global $ZBSCRM_t, $wpdb; + $resArr = $contact; - if($id > 0){ - //then run the queries.. - $nextSQL = $this->prepare("SELECT MIN(ID) FROM ".$ZBSCRM_t['contacts']." WHERE ID > %d", $id); + $resArr['avatar'] = $zbs->DAL->contacts->getContactAvatar( $resArr['id'] ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - $res['next'] = $wpdb->get_var($nextSQL); + // use created original $resArr['created'] = zeroBSCRM_date_i18n(-1, $resArr['createduts']); - $prevSQL = $this->prepare("SELECT MAX(ID) FROM ".$ZBSCRM_t['contacts']." WHERE ID < %d", $id); + #} Custom columns - $res['prev'] = $wpdb->get_var($prevSQL); + #} Total value + if ( in_array( 'totalvalue', $columnsRequired ) ) { - return $res; + #} Calc total value + add to return array + $resArr['totalvalue'] = zeroBSCRM_formatCurrency( 0 ); + if ( isset( $contact['total_value'] ) ) { + $resArr['totalvalue'] = zeroBSCRM_formatCurrency( $contact['total_value'] ); + } + } - } + #} Quotes + if ( in_array( 'quotetotal', $columnsRequired ) ) { + if ( isset( $contact['quotes_total'] ) ) { + $resArr['quotestotal'] = zeroBSCRM_formatCurrency( $contact['quotes_total'] ); + } else { + $resArr['quotestotal'] = zeroBSCRM_formatCurrency( 0 ); + } + } - return false; + #} Invoices + if ( in_array( 'invoicetotal', $columnsRequired ) ) { + if ( isset( $contact['invoices_total'] ) ) { + $resArr['invoicestotal'] = zeroBSCRM_formatCurrency( $contact['invoices_total'] ); + } else { + $resArr['invoicestotal'] = zeroBSCRM_formatCurrency( 0 ); + } + } - } + #} Transactions + if ( in_array( 'transactiontotal', $columnsRequired, true ) ) { + if ( isset( $contact['transactions_total'] ) ) { + $resArr['transactionstotal'] = zeroBSCRM_formatCurrency( $contact['transactions_total'] ); + } else { + $resArr['transactionstotal'] = zeroBSCRM_formatCurrency( 0 ); + } + } + // v3.0 + if ( isset( $contact['transactions_total'] ) ) { + // DAL2 way, brutal effort. + $resArr['transactions_total'] = zeroBSCRM_formatCurrency( $contact['transactions_total'] ); - /** - * 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($contact=false,$columnsRequired=array()){ + // also pass total without formatting (used for hastransactions check) + $resArr['transactions_total_value'] = $contact['transactions_total']; - if (is_array($contact) && isset($contact['id'])){ + } - global $zbs; + #} Company + if ( in_array( 'company', $columnsRequired ) ) { - $resArr = $contact; + $resArr['company'] = false; - $resArr['avatar'] = $zbs->DAL->contacts->getContactAvatar( $resArr['id'] ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - - // use created original $resArr['created'] = zeroBSCRM_date_i18n(-1, $resArr['createduts']); + #} Co Name Default + $coName = ''; - #} Custom columns - - #} Total value - if (in_array('totalvalue', $columnsRequired)){ + // glob as used above 1 step in ajax. not pretty + global $companyNameCache; - #} Calc total value + add to return array - $resArr['totalvalue'] = zeroBSCRM_formatCurrency(0); if (isset($contact['total_value'])) $resArr['totalvalue'] = zeroBSCRM_formatCurrency($contact['total_value']); + // get + $coID = zeroBS_getCustomerCompanyID( $resArr['id'] );// get_post_meta($post->ID,'zbs_company',true); + if ( ! empty( $coID ) ) { - } + // cache as we go + if ( ! isset( $companyNameCache[ $coID ] ) ) { + // get + $co = zeroBS_getCompany( $coID ); + if ( isset( $co ) && isset( $co['name'] ) ) { + $coName = $co['name']; + } + if ( empty( $coName ) ) { + $coName = jpcrm_label_company() . ' #' . $co['id']; + } - #} Quotes - if ( in_array( 'quotetotal', $columnsRequired ) ) { - if ( isset( $contact['quotes_total'] ) ) { - $resArr['quotestotal'] = zeroBSCRM_formatCurrency( $contact['quotes_total'] ); - } - else { - $resArr['quotestotal'] = zeroBSCRM_formatCurrency( 0 ); - } - } + // cache + $companyNameCache[ $coID ] = $coName; - #} Invoices - if ( in_array('invoicetotal', $columnsRequired ) ) { - if ( isset( $contact['invoices_total'] ) ) { - $resArr['invoicestotal'] = zeroBSCRM_formatCurrency( $contact['invoices_total'] ); - } - else { - $resArr['invoicestotal'] = zeroBSCRM_formatCurrency( 0 ); - } - } + } else { + $coName = $companyNameCache[ $coID ]; + } + } - #} Transactions - // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, Generic.WhiteSpace.DisallowSpaceIndent, Generic.WhiteSpace.ScopeIndent - if ( in_array( 'transactiontotal', $columnsRequired, true ) ) { + if ( $coID > 0 ) { + $resArr['company'] = array( + 'id' => $coID, + 'name' => $coName, + ); + } + } - if ( isset( $contact['transactions_total'] ) ) { - $resArr['transactionstotal'] = zeroBSCRM_formatCurrency( $contact['transactions_total'] ); - } else { - $resArr['transactionstotal'] = zeroBSCRM_formatCurrency( 0 ); - } - } - // phpcs:enable - // v3.0 - if (isset($contact['transactions_total'])){ + // Object view. Escaping JS for Phone link attr to avoid XSS + // phpcs:disable + $resArr['hometel'] = isset( $resArr['hometel'] ) ? esc_js( $resArr['hometel'] ) : ''; + $resArr['worktel'] = isset( $resArr['worktel'] ) ? esc_js( $resArr['worktel'] ) : ''; + $resArr['mobtel'] = isset( $resArr['mobtel'] ) ? esc_js( $resArr['mobtel'] ) : ''; + // phpcs:enable - // DAL2 way, brutal effort. - $resArr['transactions_total'] = zeroBSCRM_formatCurrency($contact['transactions_total']); + return $resArr; + } - // also pass total without formatting (used for hastransactions check) - $resArr['transactions_total_value'] = $contact['transactions_total']; + return false; + } - } + // =============================================================================== + // ============ Formatting =================================================== - #} Company - if (in_array('company',$columnsRequired)){ + /** + * Returns a formatted full name (e.g. Mr. Dave Davids) + * + * @param array $obj (tidied db obj) + * + * @return string fullname + */ + public function format_fullname( $contactArr = array() ) { - $resArr['company'] = false; + $usePrefix = zeroBSCRM_getSetting( 'showprefix' ); - #} Co Name Default - $coName = ''; + $str = ''; + if ( $usePrefix ) { + if ( isset( $contactArr['prefix'] ) ) { + $str .= $contactArr['prefix']; + } + } - // glob as used above 1 step in ajax. not pretty - global $companyNameCache; + if ( isset( $contactArr['fname'] ) ) { + if ( ! empty( $str ) ) { + $str .= ' '; + } + $str .= $contactArr['fname']; + } + if ( isset( $contactArr['lname'] ) ) { + if ( ! empty( $str ) ) { + $str .= ' '; + } + $str .= $contactArr['lname']; + } - // get - $coID = zeroBS_getCustomerCompanyID($resArr['id']);//get_post_meta($post->ID,'zbs_company',true); - if (!empty($coID)){ + return $str; + } + + /** + * Returns a formatted full name +- id, address (e.g. Mr. Dave Davids 12 London Street #23) + * Replaces zeroBS_customerName from DAL1 more realistically than format_fullname + * + * @param array $obj (tidied db obj) + * + * @return string fullname + */ + public function format_name_etc( $contactArr = 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 ============= - // cache as we go - if (!isset($companyNameCache[$coID])){ + // full name first + $str = $this->format_fullname( $contactArr ); - // get - $co = zeroBS_getCompany($coID); - if (isset($co) && isset($co['name'])) $coName = $co['name']; - if (empty($coName)) $coName = jpcrm_label_company().' #'.$co['id']; + // First line of addr? + if ( $incFirstLineAddr ) { + if ( isset( $contactArr['addr1'] ) && ! empty( $contactArr['addr1'] ) ) { + $str .= ' (' . $contactArr['addr1'] . ')'; + } + } - // cache - $companyNameCache[$coID] = $coName; + // ID? + if ( $incID ) { + $str .= ' #' . $contactArr['id']; + } - } else { - $coName = $companyNameCache[$coID]; - } - } + return $str; + } + + /** + * Returns a formatted name (e.g. Dave Davids) or fallback + * If there is no name, return "Contact #" or a provided hard-coded fallback. Optionally return an email if it exists. + * + * @param array $contactArr (tidied db obj) + * @param boolean $do_email_fallback + * @param string $hardcoded_fallback + * + * @return string name or fallback + */ + public function format_name_with_fallback( $contactArr = array(), $do_email_fallback = true, $hardcoded_fallback = '' ) { + + $str = $this->format_fullname( $contactArr ); + + if ( $do_email_fallback && empty( $str ) && ! empty( $contactArr['email'] ) ) { + $str = $contactArr['email']; + } - if ($coID > 0){ - $resArr['company'] = array('id'=>$coID,'name'=>$coName); - } - } + if ( empty( $str ) ) { + if ( ! empty( $hardcoded_fallback ) ) { + return $hardcoded_fallback; + } else { + return __( 'Contact', 'zero-bs-crm' ) . ' #' . $contactArr['id']; + } + } - // Object view. Escaping JS for Phone link attr to avoid XSS - // phpcs:disable - $resArr['hometel'] = isset( $resArr['hometel'] ) ? esc_js( $resArr['hometel'] ) : ''; - $resArr['worktel'] = isset( $resArr['worktel'] ) ? esc_js( $resArr['worktel'] ) : ''; - $resArr['mobtel'] = isset( $resArr['mobtel'] ) ? esc_js( $resArr['mobtel'] ) : ''; - // phpcs:enable + return $str; + } - return $resArr; - } - - return false; - - } - - - // =============================================================================== - // ============ Formatting =================================================== - - - /** - * Returns a formatted full name (e.g. Mr. Dave Davids) - * - * @param array $obj (tidied db obj) - * - * @return string fullname - */ - public function format_fullname($contactArr=array()){ - - $usePrefix = zeroBSCRM_getSetting('showprefix'); - - $str = ''; - if($usePrefix){ - if (isset($contactArr['prefix'])) $str .= $contactArr['prefix']; - } - - if (isset($contactArr['fname'])) { - if (!empty($str)) $str .= ' '; - $str .= $contactArr['fname']; - } - if (isset($contactArr['lname'])) { - if (!empty($str)) $str .= ' '; - $str .= $contactArr['lname']; - } - - return $str; - } - - /** - * Returns a formatted full name +- id, address (e.g. Mr. Dave Davids 12 London Street #23) - * Replaces zeroBS_customerName from DAL1 more realistically than format_fullname - * - * @param array $obj (tidied db obj) - * - * @return string fullname - */ - public function format_name_etc($contactArr=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 ============= - - // full name first - $str = $this->format_fullname($contactArr); - - // First line of addr? - if ($incFirstLineAddr) if (isset($contactArr['addr1']) && !empty($contactArr['addr1'])) $str .= ' ('.$contactArr['addr1'].')'; - - // ID? - if ($incID) $str .= ' #'.$contactArr['id']; - - return $str; - } - - /** - * Returns a formatted name (e.g. Dave Davids) or fallback - * If there is no name, return "Contact #" or a provided hard-coded fallback. Optionally return an email if it exists. - * - * @param array $contactArr (tidied db obj) - * @param boolean $do_email_fallback - * @param string $hardcoded_fallback - * - * @return string name or fallback - * - */ - public function format_name_with_fallback( $contactArr=array(), $do_email_fallback=true, $hardcoded_fallback='') { - - $str = $this->format_fullname( $contactArr ); - - if ($do_email_fallback && empty( $str ) && !empty( $contactArr['email']) ) { - $str = $contactArr['email']; - } - - if ( empty($str) ) { - if ( !empty( $hardcoded_fallback ) ) { - return $hardcoded_fallback; - } else { - return __('Contact','zero-bs-crm') . ' #' . $contactArr['id']; - } - } - - 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..d6c3deed2f4a 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.EventReminders.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.EventReminders.php @@ -1,5 +1,5 @@ -> 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..cdbe94b650bb 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Events.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Events.php @@ -1,5 +1,5 @@ -> 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,1832 +145,2036 @@ 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 + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable // quick addition for mike #} olderThan - if ( ! empty( $olderThan ) && $olderThan > 0 ) $wheres['olderThan'] = array( 'zbse_created', '<=', '%d', $olderThan ); + if ( ! empty( $olderThan ) && $olderThan > 0 ) { + $wheres['olderThan'] = array( 'zbse_created', '<=', '%d', $olderThan ); + } #} newerThan - if ( ! empty( $newerThan ) && $newerThan > 0 ) $wheres['newerThan'] = array( 'zbse_created', '>=', '%d', $newerThan ); + if ( ! empty( $newerThan ) && $newerThan > 0 ) { + $wheres['newerThan'] = array( 'zbse_created', '>=', '%d', $newerThan ); + } #} datedBefore - if ( ! empty( $datedBefore ) && $datedBefore > 0 ) $wheres['datedBefore'] = array( 'zbse_start', '<=', '%d', $datedBefore ); + if ( ! empty( $datedBefore ) && $datedBefore > 0 ) { + $wheres['datedBefore'] = array( 'zbse_start', '<=', '%d', $datedBefore ); + } #} datedAfter - if ( ! empty( $datedAfter ) && $datedAfter > 0 ) $wheres['datedAfter'] = array( 'zbse_start', '>=', '%d', $datedAfter ); + if ( ! empty( $datedAfter ) && $datedAfter > 0 ) { + $wheres['datedAfter'] = array( 'zbse_start', '>=', '%d', $datedAfter ); + } // assignedContact + assignedCompany - if ( ! empty( $assignedContact ) && $assignedContact > 0 ) $wheres['assignedContact'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TASK . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_to = %d)', $assignedContact ); - 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 + if ( ! empty( $assignedContact ) && $assignedContact > 0 ) { + $wheres['assignedContact'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_TASK . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_to = %d)', $assignedContact ); + } + 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 - // 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; - - } - + // 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 { - - // tidy - $resArr = $this->tidy_event($resDataLine,$withCustomFields); + } elseif ( is_array( $isNotTagged ) && count( $isNotTagged ) > 0 ) { - } - - 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; - - } - } - - 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..73801a6cf476 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Forms.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Forms.php @@ -1,5 +1,5 @@ -> 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 + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable // quick addition for mike #} olderThan - if ( ! empty( $olderThan ) && $olderThan > 0 ) $wheres['olderThan'] = array( 'zbsf_created', '<=', '%d', $olderThan ); + if ( ! empty( $olderThan ) && $olderThan > 0 ) { + $wheres['olderThan'] = array( 'zbsf_created', '<=', '%d', $olderThan ); + } #} newerThan - 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 + if ( ! empty( $newerThan ) && $newerThan > 0 ) { + $wheres['newerThan'] = array( 'zbsf_created', '>=', '%d', $newerThan ); + } + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - #} 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..63983f4d0dd4 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Invoices.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Invoices.php @@ -1,5 +1,5 @@ -> 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: - protected $objectType = ZBS_TYPE_INVOICE; - protected $objectDBPrefix = 'zbsi_'; - protected $include_in_templating = true; - protected $objectModel = array( + $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) + OLD hard-typed: - /* + $zbsCustomerInvoiceFields = array( - NOTE: + 'status' => array( + 'select', 'Status','',array( + 'Draft', 'Unpaid', 'Paid', 'Overdue', 'Deleted' + ), 'essential' => true + ), - $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! 'no' should now be ignored, (deprecated), moved to separate meta 'zbsid' - OLD hard-typed: - - $zbsCustomerInvoiceFields = array( + // NOTE WH: when I hit this with column manager, loads didn't need to be shown + // so plz leave ,'nocolumn'=>true in tact :) - 'status' => array( - 'select', 'Status','',array( - 'Draft', 'Unpaid', 'Paid', 'Overdue', 'Deleted' - ), 'essential' => true - ), + //'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), - # NOTE! 'no' should now be ignored, (deprecated), moved to separate meta 'zbsid' + '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 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 +265,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,608 +317,699 @@ 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 ); + } - #} ============ / PRE-QUERY =========== + // 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, + ) + ); + } - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['invoices'].' as invoice'; - #} ============= WHERE ================ + // generic get count of (EVERYTHING) + public function getFullCount() { - if (!empty($id) && $id > 0){ + return $this->getInvoices( + array( + 'count' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } - #} Add ID - $wheres['ID'] = array('ID','=','%d',$id); + /** + * 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($idOverride) && $idOverride > 0){ + global $zbs; - #} Add idOverride - $wheres['idOverride'] = array('zbsi_id_override','=','%d',$idOverride); + #} =========== 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; - } + } + } + } - /* 3.0.13 WH removed - individual getInvoice should not have searchPhrase. - #} Add Search phrase - if (!empty($searchPhrase)){ + $selector = 'invoice.*'; + if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + $selector = ''; - // 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.'%'); + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'invoice.ID'; + } - // 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.'%'); + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; + } + $selector .= 'invoice.' . $f; + } + } elseif ( $onlyID ) { + $selector = 'invoice.ID'; + } - } + #} ============ / PRE-QUERY =========== - // 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'])){ + #} Build query + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['invoices'] . ' as invoice'; + #} ============= WHERE ================ - // add it - $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); + if ( ! empty( $id ) && $id > 0 ) { - } + #} Add ID + $wheres['ID'] = array( 'ID', '=', '%d', $id ); - } */ - - if (!empty($hash)){ + } - #} Add hash - $wheres['hash'] = array('zbsi_hash','=','%s',$hash); + if ( ! empty( $idOverride ) && $idOverride > 0 ) { - } - - if (!empty($externalSource) && !empty($externalSourceUID)){ + #} Add idOverride + $wheres['idOverride'] = array( 'zbsi_id_override', '=', '%d', $idOverride ); - $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)); + } - } + /* + 3.0.13 WH removed - individual getInvoice should not have searchPhrase. + #} Add Search phrase + if (!empty($searchPhrase)){ - #} ============ / WHERE ============== + // 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.'%'); - #} Build out any WHERE clauses - $wheresArr = $this->buildWheres($wheres,$whereStr,$params); - $whereStr = $wheresArr['where']; $params = $params + $wheresArr['params']; - #} / Build WHERE + // 3.0.13 - Added ability to search custom fields (optionally) + $customFieldSearch = zeroBSCRM_getSetting('customfieldsearch'); + if ($customFieldSearch == 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 + // 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.'%'); - #} 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 { + // 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); - #} Prep & run query - $queryObj = $this->prepare($query,$params); - $potentialRes = $wpdb->get_row($queryObj, OBJECT); + if (is_array($searchQueryArr) && isset($searchQueryArr['where']) && !empty($searchQueryArr['where'])){ - } catch (Exception $e){ + // add it + $wheres['direct'][] = array('('.$searchQueryArr['where'].')',$searchQueryArr['params']); - #} General SQL Err - $this->catchSQLError($e); + } - } + } */ - #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + if ( ! empty( $hash ) ) { - #} 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); - } + #} Add hash + $wheres['hash'] = array( 'zbsi_hash', '=', '%s', $hash ); - 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))); - - } + if ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) { - if ($withTransactions){ + $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 transaction item lines - $res['transactions'] = $this->DAL()->transactions->getTransactions(array('assignedInvoice'=>$potentialRes->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_TRANSACTION))); - - } + } - if ($withAssigned){ + #} ============ / WHERE ============== - /* This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + #} Build out any WHERE clauses + $wheresArr = $this->buildWheres( $wheres, $whereStr, $params ); + $whereStr = $wheresArr['where']; + $params = $params + $wheresArr['params']; + #} / Build WHERE - // 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))); + #} 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['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_INVOICE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + #} Append to sql (this also automatically deals with sortby and paging) + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( 'ID', 'DESC' ) . $this->buildPaging( 0, 1 ); - .. but we use 1:1, at least now: */ + try { - // 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))); + #} Prep & run query + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - $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))); + } catch ( Exception $e ) { - - } + #} General SQL Err + $this->catchSQLError( $e ); - if ($withTags){ + } - // 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); - - } + #} Interpret Results (ROW) + if ( isset( $potentialRes ) && isset( $potentialRes->ID ) ) { - if ($withTotals){ + #} Has results, tidy + return - // add all tags lines - $res['totals'] = $this->generateTotalsTable($res); + #} 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 ); + } - return $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 ), + ) + ); - } // / if ID + } - return false; + if ( $withTransactions ) { - } + // add all transaction item lines + $res['transactions'] = $this->DAL()->transactions->getTransactions( + array( + 'assignedInvoice' => $potentialRes->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_TRANSACTION ), + ) + ); - /** - * returns invoice detail lines - * - * @param array $args Associative array of arguments - * - * @return array of invoice lines - */ - public function getInvoices($args=array()){ + } - global $zbs; + 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 ), + ) + ); - #} ============ 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 + if ( $withTags ) { - // 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 + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_INVOICE, + 'objid' => $potentialRes->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' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_INVOICE), // this'll let you not-check the owner of obj + if ( $withFiles ) { + $res['files'] = zeroBSCRM_files_getFiles( 'invoice', $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 ============= + } - global $ZBSCRM_t,$wpdb,$zbs; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $joinQ = ''; $extraSelect = ''; + if ( $withTotals ) { - #} ============= PRE-QUERY ============ + // add all tags lines + $res['totals'] = $this->generateTotalsTable( $res ); - #} 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; - } + return $res; - #} If onlyColumns, validate - if ($onlyColumns){ + } + } // / if ID + + return false; + } + + /** + * 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){ + #} 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 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 = 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 + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable // quick addition for mike #} olderThan - if ( ! empty( $olderThan ) && $olderThan > 0 ) $wheres['olderThan'] = array( 'zbsi_created', '<=', '%d', $olderThan ); + if ( ! empty( $olderThan ) && $olderThan > 0 ) { + $wheres['olderThan'] = array( 'zbsi_created', '<=', '%d', $olderThan ); + } #} newerThan - if ( ! empty( $newerThan ) && $newerThan > 0 ) $wheres['newerThan'] = array( 'zbsi_created', '>=', '%d', $newerThan ); + if ( ! empty( $newerThan ) && $newerThan > 0 ) { + $wheres['newerThan'] = array( 'zbsi_created', '>=', '%d', $newerThan ); + } // status - if ( ! empty( $hasStatus ) ) $wheres['hasStatus'] = array( 'zbsi_status', '=', '%s', $hasStatus ); - if ( ! empty( $otherStatus ) ) $wheres['otherStatus'] = array( 'zbsi_status', '<>', '%s', $otherStatus ); + if ( ! empty( $hasStatus ) ) { + $wheres['hasStatus'] = array( 'zbsi_status', '=', '%s', $hasStatus ); + } + if ( ! empty( $otherStatus ) ) { + $wheres['otherStatus'] = array( 'zbsi_status', '<>', '%s', $otherStatus ); + } // assignedContact + assignedCompany - if ( ! empty( $assignedContact ) && $assignedContact > 0 ) $wheres['assignedContact'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_to = %d)', $assignedContact ); - if ( ! empty( $assignedCompany ) && $assignedCompany > 0 ) $wheres['assignedCompany'] = array( 'ID', 'IN', '(SELECT 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 = %d)', $assignedCompany ); - // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed + if ( ! empty( $assignedContact ) && $assignedContact > 0 ) { + $wheres['assignedContact'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_INVOICE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_to = %d)', $assignedContact ); + } + if ( ! empty( $assignedCompany ) && $assignedCompany > 0 ) { + $wheres['assignedCompany'] = array( 'ID', 'IN', '(SELECT 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 = %d)', $assignedCompany ); + } + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - #} 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 +1017,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 ) { + + if ( $tagStr !== '' ) { + $tagStr . ','; + } + $tagStr .= $i; + } + } + if ( ! empty( $tagStr ) ) { - // foreach in array :) - $tagStr = ''; - foreach ($isTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + $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) - } + // catch 1 item arr + if ( is_array( $isNotTagged ) && count( $isNotTagged ) == 1 ) { + $isNotTagged = $isNotTagged[0]; + } - } - #} Is NOT Tagged (expects 1 tag ID OR array) + 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 = invoice.ID AND zbstl_tagid = %d) = 0)', array( ZBS_TYPE_INVOICE, $isNotTagged ) ); - if ( ! empty( $isNotTagged ) && ! is_array( $isNotTagged ) && $isNotTagged > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } elseif ( 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 = invoice.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_INVOICE,$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 ) ) { - // foreach in array :) - $tagStr = ''; - foreach ($isNotTagged as $iTag){ - $i = (int)$iTag; - if ($i > 0){ + $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']])){ + if ( isset( $customFields[ $field['key'] ] ) ) { - // is custom, move to data - $data[$field['key']] = $field['val']; + // is custom, move to data + $data[ $field['key'] ] = $field['val']; - } else if (!empty($dePrefixed) && isset($customFields[$dePrefixed])){ + } elseif ( ! empty( $dePrefixed ) && isset( $customFields[ $dePrefixed ] ) ) { - // is custom, move to data - $data[$dePrefixed] = $field['val']; + // 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); - - } + } 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 +2741,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 +3056,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 +3103,27 @@ public function get_invoice_status_except_deleted_for_query( $table_alias_sql = * * @return string invoice hash string */ - public function getInvoiceHash($id=-1){ - - global $zbs; + public function getInvoiceHash( $id = -1 ) { - $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 +3132,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'] ) ) { + if ( isset( $invoice['total'] ) ) { + $invoice_total_value = (float) $invoice['total']; + // this one'll be a rolling sum + $transactions_total_value = 0.0; - // got trans - foreach ( $invoice['transactions'] as $transaction ) { + // cycle through trans + calc existing balance + if ( isset( $invoice['transactions'] ) && is_array( $invoice['transactions'] ) ) { - // should we also check for status=completed/succeeded? (leaving for now, will let check all): + // got trans + foreach ( $invoice['transactions'] as $transaction ) { - // get amount - $transaction_amount = 0.0; + // should we also check for status=completed/succeeded? (leaving for now, will let check all): - if ( isset( $transaction['total'] ) ) { - $transaction_amount = (float) $transaction['total']; + // get amount + $transaction_amount = 0.0; - if ( $transaction_amount > 0 ) { + if ( isset( $transaction['total'] ) ) { + $transaction_amount = (float) $transaction['total']; - switch ( $transaction['type'] ) { - case __( 'Sale', 'zero-bs-crm' ): - // these count as debits against invoice. - $transactions_total_value -= $transaction_amount; + if ( $transaction_amount > 0 ) { - break; + switch ( $transaction['type'] ) { + case __( 'Sale', 'zero-bs-crm' ): + // these count as debits against invoice. + $transactions_total_value -= $transaction_amount; - case __( 'Refund', 'zero-bs-crm' ): - case __( 'Credit Note', 'zero-bs-crm' ): - // these count as credits against invoice. - $transactions_total_value += $transaction_amount; + break; - break; + case __( 'Refund', 'zero-bs-crm' ): + case __( 'Credit Note', 'zero-bs-crm' ): + // these count as credits against invoice. + $transactions_total_value += $transaction_amount; - } // / switch on type (sale/refund) + break; - } // / if trans > 0 + } // / switch on type (sale/refund) - } // / if isset + } // / if trans > 0 - } // / each trans + } // / if isset - // should now have $transactions_total_value & $invoice_total_value - // ... so we sum + return. - return $invoice_total_value + $transactions_total_value; + } // / each trans - } // / if has trans - } // if isset invoice total + // should now have $transactions_total_value & $invoice_total_value + // ... so we sum + return. + return $invoice_total_value + $transactions_total_value; - } // / if retrieved inv + } // / if has trans + } // if isset invoice total - } // / if invoice_id > 0 + } // / if retrieved inv - 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){ - - // 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 +1340,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..f994e5c62fae 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Logs.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Logs.php @@ -1,5 +1,5 @@ -> 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..337916e01eb0 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.QuoteTemplates.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.QuoteTemplates.php @@ -1,5 +1,5 @@ -> 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 + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable // quick addition for mike #} olderThan - if ( ! empty( $olderThan ) && $olderThan > 0 ) $wheres['olderThan'] = array( 'zbsqt_created', '<=', '%d', $olderThan ); + if ( ! empty( $olderThan ) && $olderThan > 0 ) { + $wheres['olderThan'] = array( 'zbsqt_created', '<=', '%d', $olderThan ); + } #} newerThan - 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 + if ( ! empty( $newerThan ) && $newerThan > 0 ) { + $wheres['newerThan'] = array( 'zbsqt_created', '>=', '%d', $newerThan ); + } + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + + #} 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 +577,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.Quotes.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Quotes.php index 2c31169f534d..39320922a0a3 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Quotes.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Quotes.php @@ -1,5 +1,6 @@ -> Quotes -* -* @author Woody Hayday -* @version 2.0 -* @access public -* @see https://jetpackcrm.com/kb -*/ + * ZBS DAL >> Quotes + * + * @author Woody Hayday + * @version 2.0 + * @access public + * @see https://jetpackcrm.com/kb + */ class zbsDAL_quotes extends zbsDAL_ObjectLayer { - protected $objectType = ZBS_TYPE_QUOTE; - protected $objectDBPrefix = 'zbsq_'; - protected $include_in_templating = true; - protected $objectModel = array( - + protected $objectType = ZBS_TYPE_QUOTE; + protected $objectDBPrefix = 'zbsq_'; + protected $include_in_templating = true; + 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 'id_override' => array( - 'fieldname' => 'zbsq_id_override', - 'format' => 'str', - 'max_len' => 128 + 'fieldname' => 'zbsq_id_override', + 'format' => 'str', + 'max_len' => 128, ), - 'title' => array( - // db model: - 'fieldname' => 'zbsq_title', 'format' => 'str', - // output model - 'input_type' => 'text', - 'label' => 'Quote Title', - 'placeholder'=> 'e.g. New Website', - 'essential' => true, - 'dal1key' => 'name', - 'max_len' => 255 - ), - 'currency' => array( - 'fieldname' => 'zbsq_currency', - 'format' => 'curr', - 'max_len' => 4 - ), - 'value' => array( - // db model: - 'fieldname' => 'zbsq_value', 'format' => 'decimal', - // output model - 'input_type' => 'price', - 'label' => 'Quote Value', - 'placeholder'=> 'e.g. 500.00', - 'essential' => true, - 'dal1key' => 'val' - ), - 'date' => array( - // db model: - 'fieldname' => 'zbsq_date', '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' => 'Quote Date', - 'placeholder'=>'', - 'essential' => true - ), - 'template' => array('fieldname' => 'zbsq_template', 'format' => 'str'), - 'content' => array('fieldname' => 'zbsq_content', 'format' => 'str'), - 'notes' => array( - // db model: - 'fieldname' => 'zbsq_notes', 'format' => 'str', - // output model - 'input_type' => 'textarea', - 'label' => 'Notes', - 'placeholder'=>'' - - ), - 'send_attachments' => array('fieldname' => 'zbsq_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 - 'hash' => array('fieldname' => 'zbsq_hash', 'format' => 'str'), - 'lastviewed' => array('fieldname' => 'zbsq_lastviewed', 'format' => 'uts'), - 'viewed_count' => array('fieldname' => 'zbsq_viewed_count', 'format' => 'int'), - 'accepted' => array('fieldname' => 'zbsq_accepted', 'format' => 'uts'), - 'acceptedsigned' => array( - 'fieldname' => 'zbsq_acceptedsigned', - 'format' => 'str', - 'max_len' => 200 + 'title' => array( + // db model: + 'fieldname' => 'zbsq_title', + 'format' => 'str', + // output model + 'input_type' => 'text', + 'label' => 'Quote Title', + 'placeholder' => 'e.g. New Website', + 'essential' => true, + 'dal1key' => 'name', + 'max_len' => 255, ), - 'acceptedip' => array( - 'fieldname' => 'zbsq_acceptedip', - 'format' => 'str', - 'max_len' => 64 + 'currency' => array( + 'fieldname' => 'zbsq_currency', + 'format' => 'curr', + 'max_len' => 4, ), - 'created' => array('fieldname' => 'zbsq_created', 'format' => 'uts'), - 'lastupdated' => array('fieldname' => 'zbsq_lastupdated', 'format' => 'uts'), - - ); + 'value' => array( + // db model: + 'fieldname' => 'zbsq_value', + 'format' => 'decimal', + // output model + 'input_type' => 'price', + 'label' => 'Quote Value', + 'placeholder' => 'e.g. 500.00', + 'essential' => true, + 'dal1key' => 'val', + ), + 'date' => array( + // db model: + 'fieldname' => 'zbsq_date', + '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' => 'Quote Date', + 'placeholder' => '', + 'essential' => true, + ), + 'template' => array( + 'fieldname' => 'zbsq_template', + 'format' => 'str', + ), + 'content' => array( + 'fieldname' => 'zbsq_content', + 'format' => 'str', + ), + 'notes' => array( + // db model: + 'fieldname' => 'zbsq_notes', + 'format' => 'str', + // output model + 'input_type' => 'textarea', + 'label' => 'Notes', + 'placeholder' => '', - // hardtyped list of types this object type is commonly linked to - protected $linkedToObjectTypes = array( + ), + 'send_attachments' => array( + 'fieldname' => 'zbsq_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 + 'hash' => array( + 'fieldname' => 'zbsq_hash', + 'format' => 'str', + ), + 'lastviewed' => array( + 'fieldname' => 'zbsq_lastviewed', + 'format' => 'uts', + ), + 'viewed_count' => array( + 'fieldname' => 'zbsq_viewed_count', + 'format' => 'int', + ), + 'accepted' => array( + 'fieldname' => 'zbsq_accepted', + 'format' => 'uts', + ), + 'acceptedsigned' => array( + 'fieldname' => 'zbsq_acceptedsigned', + 'format' => 'str', + 'max_len' => 200, + ), + 'acceptedip' => array( + 'fieldname' => 'zbsq_acceptedip', + 'format' => 'str', + 'max_len' => 64, + ), + 'created' => array( + 'fieldname' => 'zbsq_created', + 'format' => 'uts', + ), + 'lastupdated' => array( + 'fieldname' => 'zbsq_lastupdated', + 'format' => 'uts', + ), - ZBS_TYPE_CONTACT + ); - ); + // hardtyped list of types this object type is commonly linked to + protected $linkedToObjectTypes = array( + ZBS_TYPE_CONTACT, - function __construct($args=array()) { + ); + 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 ============= - add_filter( 'jpcrm_listview_filters', array( $this, 'add_listview_filters' ) ); + add_filter( 'jpcrm_listview_filters', array( $this, 'add_listview_filters' ) ); } - /** - * Adds items to listview filter using `jpcrm_listview_filters` hook. - * - * @param array $listview_filters Listview filters. - */ - public function add_listview_filters( $listview_filters ) { - global $zbs; - // Add statuses if enabled. - if ( $zbs->settings->get( 'filtersfromstatus' ) === 1 ) { - $statuses = array( - 'draft' => __( 'Draft', 'zero-bs-crm' ), - 'accepted' => __( 'Accepted', 'zero-bs-crm' ), - 'notaccepted' => __( 'Not Accepted', 'zero-bs-crm' ), - ); - foreach ( $statuses as $status_slug => $status_label ) { - $listview_filters[ ZBS_TYPE_QUOTE ]['status'][ 'status_' . $status_slug ] = $status_label; - } + /** + * Adds items to listview filter using `jpcrm_listview_filters` hook. + * + * @param array $listview_filters Listview filters. + */ + public function add_listview_filters( $listview_filters ) { + global $zbs; + // Add statuses if enabled. + if ( $zbs->settings->get( 'filtersfromstatus' ) === 1 ) { + $statuses = array( + 'draft' => __( 'Draft', 'zero-bs-crm' ), + 'accepted' => __( 'Accepted', 'zero-bs-crm' ), + 'notaccepted' => __( 'Not Accepted', 'zero-bs-crm' ), + ); + foreach ( $statuses as $status_slug => $status_label ) { + $listview_filters[ ZBS_TYPE_QUOTE ]['status'][ 'status_' . $status_slug ] = $status_label; } - return $listview_filters; } + return $listview_filters; + } // =============================================================================== // =========== QUOTE ======================================================= - // 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->getQuote($ID); - - } - - // generic get (by ID list) - // Super simplistic wrapper used by MVP Export v3.0 - public function getIDList($IDs=false){ - - return $this->getQuotes(array( - 'inArr' => $IDs, - 'withOwner' => true, - 'withAssigned' => true, - 'page' => -1, - 'perPage' => -1 - )); - - } - - // generic get (EVERYTHING) - // expect heavy load! - public function getAll($IDs=false){ - - return $this->getQuotes(array( - 'withOwner' => true, - 'withAssigned' => true, - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => -1, - 'perPage' => -1, - )); - - } - - // generic get count of (EVERYTHING) - public function getFullCount(){ - - return $this->getQuotes(array( - 'count' => true, - 'page' => -1, - 'perPage' => -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->getQuote( $ID ); + } + + // generic get (by ID list) + // Super simplistic wrapper used by MVP Export v3.0 + public function getIDList( $IDs = false ) { + + return $this->getQuotes( + array( + 'inArr' => $IDs, + 'withOwner' => true, + 'withAssigned' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + // generic get (EVERYTHING) + // expect heavy load! + public function getAll( $IDs = false ) { + + return $this->getQuotes( + array( + 'withOwner' => true, + 'withAssigned' => true, + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => -1, + 'perPage' => -1, + ) + ); + } + + // generic get count of (EVERYTHING) + public function getFullCount() { + + return $this->getQuotes( + array( + 'count' => true, + 'page' => -1, + 'perPage' => -1, + ) + ); + } + /** * returns full quote line +- details * * @param int id quote id - * @param array $args Associative array of arguments + * @param array $args Associative array of arguments * * @return array quote object */ - public function getQuote($id=-1,$args=array()){ + public function getQuote( $id = -1, $args = array() ) { global $zbs; #} =========== LOAD ARGS ============== $defaultArgs = array( - // if these are passed, will search based on these + // if these are passed, will search based on these 'id_override' => false, 'externalSource' => false, 'externalSourceUID' => false, - 'hash' => false, + 'hash' => false, // with what? 'withLineItems' => true, 'withCustomFields' => true, - 'withAssigned' => true, // return ['contact'] & ['company'] objs if has link + 'withAssigned' => true, // return ['contact'] & ['company'] objs if has link 'withTags' => false, - 'withFiles' => false, + 'withFiles' => false, 'withOwner' => false, // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE), // this'll let you not-check the owner of obj + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), // this'll let you not-check the owner of obj // returns scalar ID of line - 'onlyID' => false, + 'onlyID' => false, - 'fields' => false // false = *, array = fieldnames + '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]; } } } + ); + 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; + $id = (int) $id; if ( - (!empty($id) && $id > 0) + ( ! empty( $id ) && $id > 0 ) || - (!empty($email)) - || - (!empty($hash)) + ( ! empty( $email ) ) || - (!empty($externalSource) && !empty($externalSourceUID)) - ){ - - global $ZBSCRM_t,$wpdb; - $wheres = array('direct'=>array()); $whereStr = ''; $additionalWhere = ''; $params = array(); $res = array(); $extraSelect = ''; + ( ! 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_QUOTE)); + #} Custom Fields + if ( $withCustomFields && ! $onlyID ) { + + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_QUOTE ) ); - #} 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 = quote.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '".$cK."'"; - + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . " WHERE zbscf_objid = quote.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) '" . $cK . "'"; + // add params - $params[] = $cK; $params[] = ZBS_TYPE_QUOTE; + $params[] = $cK; + $params[] = ZBS_TYPE_QUOTE; } - } + } - $selector = 'quote.*'; - if ( is_array( $fields ) ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - $selector = ''; + $selector = 'quote.*'; + 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 = 'quote.ID'; + // always needs id, so add if not present + if ( ! in_array( 'ID', $fields ) ) { + $selector = 'quote.ID'; + } - foreach ($fields as $f) { - if (!empty($selector)) $selector .= ','; - $selector .= 'quote.'.$f; + foreach ( $fields as $f ) { + if ( ! empty( $selector ) ) { + $selector .= ','; } - } else if ($onlyID){ - $selector = 'quote.ID'; + $selector .= 'quote.' . $f; } + } elseif ( $onlyID ) { + $selector = 'quote.ID'; + } #} ============ / PRE-QUERY =========== - #} Build query - $query = "SELECT ".$selector.$extraSelect." FROM ".$ZBSCRM_t['quotes'].' as quote'; + $query = 'SELECT ' . $selector . $extraSelect . ' FROM ' . $ZBSCRM_t['quotes'] . ' as quote'; #} ============= 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 ); - } - if (!empty($id_override) && $id_override > 0){ + } + if ( ! empty( $id_override ) && $id_override > 0 ) { - #} Add id_override - //$wheres['search_id'] = array('ID','LIKE','%s','%'.$id_override.'%'); - $wheres['search_id2'] = array('zbsq_id_override','LIKE','%s','%'.$id_override.'%'); + #} Add id_override + // $wheres['search_id'] = array('ID','LIKE','%s','%'.$id_override.'%'); + $wheres['search_id2'] = array( 'zbsq_id_override', 'LIKE', '%s', '%' . $id_override . '%' ); - } - - if (!empty($hash)){ + } - #} Add hash - $wheres['hash'] = array('zbsq_hash','=','%s',$hash); + if ( ! empty( $hash ) ) { - } - - if (!empty($externalSource) && !empty($externalSourceUID)){ + #} Add hash + $wheres['hash'] = array( 'zbsq_hash', '=', '%s', $hash ); - $wheres['extsourcecheck'] = array('ID','IN','(SELECT DISTINCT zbss_objid FROM '.$ZBSCRM_t['externalsources']." WHERE zbss_objtype = ".ZBS_TYPE_QUOTE." AND zbss_source = %s AND zbss_uid = %s)",array($externalSource,$externalSourceUID)); + } - } + if ( ! empty( $externalSource ) && ! empty( $externalSourceUID ) ) { + + $wheres['extsourcecheck'] = array( 'ID', 'IN', '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_QUOTE . ' 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']; + $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,'quote'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query + #} 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, 'quote' ); + 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); + $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); + $queryObj = $this->prepare( $query, $params ); + $potentialRes = $wpdb->get_row( $queryObj, OBJECT ); - } catch (Exception $e){ + } catch ( Exception $e ) { #} General SQL Err - $this->catchSQLError($e); + $this->catchSQLError( $e ); } #} Interpret Results (ROW) - if (isset($potentialRes) && isset($potentialRes->ID)) { + 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_quote($potentialRes,$withCustomFields); - } + #} Has results, tidy + return - if ($withLineItems){ + #} Only ID? return it directly + if ( $onlyID ) { + return $potentialRes->ID; + } - // add all line item lines - $res['lineitems'] = $this->DAL()->lineitems->getLineitems(array('associatedObjType'=>ZBS_TYPE_QUOTE,'associatedObjID'=>$potentialRes->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LINEITEM))); - - } - - 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_QUOTE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_QUOTE, - '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_QUOTE, - '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_QUOTE, - 'hasObjIDLinkedTo'=>$potentialRes->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); - - - } - - if ($withFiles){ - - $res['files'] = zeroBSCRM_files_getFiles('quote',$potentialRes->ID); - - } - - if ($withTags){ - - // add all tags lines - $res['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_QUOTE,'objid'=>$potentialRes->ID)); - - } + // tidy + if ( is_array( $fields ) ) { + // guesses fields based on table col names + $res = $this->lazyTidyGeneric( $potentialRes ); + } else { + // proper tidy + $res = $this->tidy_quote( $potentialRes, $withCustomFields ); + } - return $res; + if ( $withLineItems ) { - } + // add all line item lines + $res['lineitems'] = $this->DAL()->lineitems->getLineitems( + array( + 'associatedObjType' => ZBS_TYPE_QUOTE, + 'associatedObjID' => $potentialRes->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LINEITEM ), + ) + ); + + } + + 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_QUOTE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + + $res['companies'] = $this->DAL()->companies->getCompanies(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_QUOTE, + '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_QUOTE, + '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_QUOTE, + 'hasObjIDLinkedTo' => $potentialRes->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); + + } + + if ( $withFiles ) { + + $res['files'] = zeroBSCRM_files_getFiles( 'quote', $potentialRes->ID ); + + } + + if ( $withTags ) { + // add all tags lines + $res['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_QUOTE, + 'objid' => $potentialRes->ID, + ) + ); + + } + + return $res; + + } } // / if ID return false; - } /** @@ -454,7 +562,7 @@ public function getQuote($id=-1,$args=array()){ * * @return array of quote lines */ - public function getQuotes($args=array()){ + public function getQuotes( $args = array() ) { global $zbs; @@ -462,468 +570,542 @@ public function getQuotes($args=array()){ $defaultArgs = array( // Search/Filtering (leave as false to ignore) - 'searchPhrase' => '', // searches id, id override, title, content - '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 - 'hasAccepted' => false, // if TRUE only returns accepted - 'hasNotAccepted' => false, // if TRUE only returns not-accepted - 'assignedContact' => false, // assigned to contact id (int) - 'assignedCompany' => false, // assigned to company id (int) - 'quickFilters' => false, // booo + 'searchPhrase' => '', // searches id, id override, title, content + '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 + 'hasAccepted' => false, // if TRUE only returns accepted + 'hasNotAccepted' => false, // if TRUE only returns not-accepted + 'assignedContact' => false, // assigned to contact id (int) + 'assignedCompany' => false, // assigned to company id (int) + 'quickFilters' => false, // booo // returns - 'count' => false, - 'withLineItems' => true, - 'withCustomFields' => true, - 'withTags' => false, - 'withOwner' => false, - 'withAssigned' => false, // return ['contact'] & ['company'] objs if has link - 'withFiles' => false, - 'suppressContent' => false, // do not return html - '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 + 'count' => false, + 'withLineItems' => true, + 'withCustomFields' => true, + 'withTags' => false, + 'withOwner' => false, + 'withAssigned' => false, // return ['contact'] & ['company'] objs if has link + 'withFiles' => false, + 'suppressContent' => false, // do not return html + '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_QUOTE), // this'll let you not-check the owner of obj + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), // 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]; } } } + ); + 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 ============ - #} Capitalise this - $sortOrder = strtoupper($sortOrder); + #} Capitalise this + $sortOrder = strtoupper( $sortOrder ); - #} If just count, turn off any extra gumpf - if ($count) { - $withCustomFields = false; - $withTags = false; - $withFiles = false; - $withOwner = false; - $withAssigned = false; - } - - #} If onlyColumns, validate - if ($onlyColumns){ - - #} onlyColumns build out a field arr - if (is_array($onlyColumns) && count($onlyColumns) > 0){ + #} If just count, turn off any extra gumpf + if ( $count ) { + $withCustomFields = false; + $withTags = false; + $withFiles = false; + $withOwner = false; + $withAssigned = false; + } - $onlyColumnsFieldArr = array(); - foreach ($onlyColumns as $col){ + #} If onlyColumns, validate + if ( $onlyColumns ) { - // 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']; + #} onlyColumns build out a field arr + if ( is_array( $onlyColumns ) && count( $onlyColumns ) > 0 ) { - if (!empty($dbCol)){ + $onlyColumnsFieldArr = array(); + foreach ( $onlyColumns as $col ) { - $onlyColumnsFieldArr[$dbCol] = $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){ + // if legit cols: + if ( isset( $onlyColumnsFieldArr ) && is_array( $onlyColumnsFieldArr ) && count( $onlyColumnsFieldArr ) > 0 ) { - $onlyColumns = true; - - // If onlyColumns, turn off extras - $withCustomFields = false; - $withTags = false; - $withFiles = false; - $withOwner = false; - $withAssigned = false; + $onlyColumns = true; - } else { + // If onlyColumns, turn off extras + $withCustomFields = false; + $withTags = false; + $withFiles = false; + $withOwner = false; + $withAssigned = 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 ) { - #} 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_QUOTE)); + #} Retrieve any cf + $custFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_QUOTE ) ); - #} 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 ) { // 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); + $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 = quote.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ".$cKey; - + $extraSelect .= ',(SELECT zbscf_objval FROM ' . $ZBSCRM_t['customfields'] . ' WHERE zbscf_objid = quote.ID AND zbscf_objkey = %s AND zbscf_objtype = %d LIMIT 1) ' . $cKey; + // add params - $params[] = $cK; $params[] = ZBS_TYPE_QUOTE; + $params[] = $cK; + $params[] = ZBS_TYPE_QUOTE; } - } + } #} ============ / PRE-QUERY =========== #} Build query - $query = "SELECT quote.*".$extraSelect." FROM ".$ZBSCRM_t['quotes'].' as quote'.$joinQ; + $query = 'SELECT quote.*' . $extraSelect . ' FROM ' . $ZBSCRM_t['quotes'] . ' as quote' . $joinQ; #} Count override - if ($count) $query = "SELECT COUNT(quote.ID) FROM ".$ZBSCRM_t['quotes'].' as quote'.$joinQ; + if ( $count ) { + $query = 'SELECT COUNT(quote.ID) FROM ' . $ZBSCRM_t['quotes'] . ' as quote' . $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['quotes'].' as quote'.$joinQ; + $query = 'SELECT ' . $columnStr . ' FROM ' . $ZBSCRM_t['quotes'] . ' as quote' . $joinQ; - } + } #} ============= 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_id'] = array('ID','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_id_override'] = array('zbsq_id_override','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_title'] = array('zbsq_title','LIKE','%s','%'.$searchPhrase.'%'); - $searchWheres['search_content'] = array('zbsq_content','LIKE','%s','%'.$searchPhrase.'%'); + // search? - ALL THESE COLS should probs have index of FULLTEXT in db? + $searchWheres = array(); + $searchWheres['search_id'] = array( 'ID', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_id_override'] = array( 'zbsq_id_override', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_title'] = array( 'zbsq_title', 'LIKE', '%s', '%' . $searchPhrase . '%' ); + $searchWheres['search_content'] = array( 'zbsq_content', '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_QUOTE.")",'%'.$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_QUOTE . ')', '%' . $searchPhrase . '%' ); - // This generates a query like 'zbsq_fname LIKE %s OR zbsq_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']); + // This generates a query like 'zbsq_fname LIKE %s OR zbsq_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){ + #} 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){ - - // 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); + #} 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 ); - // 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_QUOTE." AND zbss_source = %s)",$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_QUOTE . ' AND zbss_source = %s)', $externalSource ); - // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable,Generic.ControlStructures.InlineControlStructure.NotAllowed - // quick addition for mike - #} olderThan - if ( ! empty( $olderThan ) && $olderThan > 0 ) $wheres['olderThan'] = array( 'zbsq_created', '<=', '%d', $olderThan ); - #} newerThan - if ( ! empty( $newerThan ) && $newerThan > 0 ) $wheres['newerThan'] = array( 'zbsq_created', '>=', '%d', $newerThan ); - - // status - if ( ! empty( $hasAccepted ) && $hasAccepted ) $wheres['hasAccepted'] = array( 'zbsq_accepted', '>', '%d', 0 ); - if ( ! empty( $hasNotAccepted ) && $hasNotAccepted ) $wheres['hasnotAccepted'] = array( 'zbsq_accepted', '<=', '%d', 0 ); - - // assignedContact + assignedCompany - if ( ! empty( $assignedContact ) && $assignedContact > 0 ) $wheres['assignedContact'] = array( 'ID', 'IN', '(SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_QUOTE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_to = %d)', $assignedContact ); - if ( ! empty( $assignedCompany ) && $assignedCompany > 0 ) $wheres['assignedCompany'] = array( 'ID', 'IN', '(SELECT 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 = %d)', $assignedCompany ); - // 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){ - - // cycle through - foreach ( $quickFilters as $quick_filter ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - - if ( $quick_filter === 'status_accepted' ) { - $wheres['quickfilterstatus'] = array( 'zbsq_accepted', '>', '0' ); - $wheres['quickfilterstatus2'] = array( 'zbsq_template', '>', '0' ); - } elseif ( $quick_filter === 'status_notaccepted' ) { - $wheres['quickfilterstatus'] = array( 'zbsq_accepted', '<=', '0' ); - $wheres['quickfilterstatus2'] = array( 'zbsq_template', '>', '0' ); - } elseif ( $quick_filter === 'status_draft' ) { - $wheres['quickfilterstatus'] = array( 'zbsq_template', '<=', '0' ); - } + } + + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + // quick addition for mike + #} olderThan + if ( ! empty( $olderThan ) && $olderThan > 0 ) { + $wheres['olderThan'] = array( 'zbsq_created', '<=', '%d', $olderThan ); + } + #} newerThan + if ( ! empty( $newerThan ) && $newerThan > 0 ) { + $wheres['newerThan'] = array( 'zbsq_created', '>=', '%d', $newerThan ); + } + + // status + if ( ! empty( $hasAccepted ) && $hasAccepted ) { + $wheres['hasAccepted'] = array( 'zbsq_accepted', '>', '%d', 0 ); + } + if ( ! empty( $hasNotAccepted ) && $hasNotAccepted ) { + $wheres['hasnotAccepted'] = array( 'zbsq_accepted', '<=', '%d', 0 ); + } + + // assignedContact + assignedCompany + if ( ! empty( $assignedContact ) && $assignedContact > 0 ) { + $wheres['assignedContact'] = array( 'ID', 'IN', '( SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_QUOTE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_to = %d)', $assignedContact ); + } + if ( ! empty( $assignedCompany ) && $assignedCompany > 0 ) { + $wheres['assignedCompany'] = array( 'ID', 'IN', '( SELECT 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 = %d)', $assignedCompany ); + } + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + + #} Quick filters - adapted from DAL1 (probs can be slicker) + if ( is_array( $quickFilters ) && count( $quickFilters ) > 0 ) { + + // cycle through + foreach ( $quickFilters as $quick_filter ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + + if ( $quick_filter === 'status_accepted' ) { + $wheres['quickfilterstatus'] = array( 'zbsq_accepted', '>', '0' ); + $wheres['quickfilterstatus2'] = array( 'zbsq_template', '>', '0' ); + } elseif ( $quick_filter === 'status_notaccepted' ) { + $wheres['quickfilterstatus'] = array( 'zbsq_accepted', '<=', '0' ); + $wheres['quickfilterstatus2'] = array( 'zbsq_template', '>', '0' ); + } elseif ( $quick_filter === 'status_draft' ) { + $wheres['quickfilterstatus'] = array( 'zbsq_template', '<=', '0' ); } - } // / 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 + 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 = quote.ID AND zbstl_tagid = %d) > 0)',array(ZBS_TYPE_QUOTE,$isTagged)); + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = quote.ID AND zbstl_tagid = %d) > 0)', array( ZBS_TYPE_QUOTE, $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 ( $tagStr !== '' ) { + $tagStr .= ','; } + $tagStr .= $i; } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quote.ID AND zbstl_tagid IN (%s)) > 0)',array(ZBS_TYPE_QUOTE,$tagStr)); + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = quote.ID AND zbstl_tagid IN (%s)) > 0)', array( ZBS_TYPE_QUOTE, $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 = quote.ID AND zbstl_tagid = %d) = 0)',array(ZBS_TYPE_QUOTE,$isNotTagged)); + // add where tagged + // 1 int: + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = quote.ID AND zbstl_tagid = %d) = 0)', array( ZBS_TYPE_QUOTE, $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 ( $tagStr !== '' ) { + $tagStr .= ','; } + $tagStr .= $i; } - if (!empty($tagStr)){ - - $wheres['direct'][] = array('((SELECT COUNT(ID) FROM '.$ZBSCRM_t['taglinks'].' WHERE zbstl_objtype = %d AND zbstl_objid = quote.ID AND zbstl_tagid IN (%s)) = 0)',array(ZBS_TYPE_QUOTE,$tagStr)); + } + if ( ! empty( $tagStr ) ) { - } + $wheres['direct'][] = array( '((SELECT COUNT(ID) FROM ' . $ZBSCRM_t['taglinks'] . ' WHERE zbstl_objtype = %d AND zbstl_objid = quote.ID AND zbstl_tagid IN (%s)) = 0)', array( ZBS_TYPE_QUOTE, $tagStr ) ); } - - + } #} ============ / 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']; + } - // Mapped sorts - // This catches listview and other exception sort cases - $sort_map = array( - 'customer' => '(SELECT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_QUOTE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_from = quote.ID)', // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - // hack to support quote statuses (for here only, 2 is accepted, 1 is unaccepted, 0 is draft) - 'status' => '(CASE WHEN zbsq_accepted > 0 THEN 2 WHEN zbsq_template > 0 THEN 1 ELSE 0 END)', - ); + // Mapped sorts + // This catches listview and other exception sort cases + $sort_map = array( + 'customer' => '(SELECT zbsol_objid_to FROM ' . $ZBSCRM_t['objlinks'] . ' WHERE zbsol_objtype_from = ' . ZBS_TYPE_QUOTE . ' AND zbsol_objtype_to = ' . ZBS_TYPE_CONTACT . ' AND zbsol_objid_from = quote.ID)', // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // hack to support quote statuses (for here only, 2 is accepted, 1 is unaccepted, 0 is draft) + 'status' => '(CASE WHEN zbsq_accepted > 0 THEN 2 WHEN zbsq_template > 0 THEN 1 ELSE 0 END)', + ); - 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'; + 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']; + $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,'quote'); if (!empty($ownQ)) $additionalWhere = $this->spaceAnd($additionalWhere).$ownQ; // adds str to query + $params = array_merge( $params, $this->ownershipQueryVars( $ignoreowner ) ); // merges in any req. + $ownQ = $this->ownershipSQL( $ignoreowner, 'quote' ); + 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); - + $query .= $this->buildWhereStr( $whereStr, $additionalWhere ) . $this->buildSort( $sortByField, $sortOrder ) . $this->buildPaging( $page, $perPage ); + try { #} Prep & run query - $queryObj = $this->prepare($query,$params); + $queryObj = $this->prepare( $query, $params ); #} Catch count + return if requested - if ($count) return $wpdb->get_var($queryObj); + if ( $count ) { + return $wpdb->get_var( $queryObj ); + } #} else continue.. - $potentialRes = $wpdb->get_results($queryObj, OBJECT); + $potentialRes = $wpdb->get_results( $queryObj, OBJECT ); - } catch (Exception $e){ + } catch ( Exception $e ) { #} General SQL Err - $this->catchSQLError($e); + $this->catchSQLError( $e ); } #} Interpret results (Result Set - multi-row) - if (isset($potentialRes) && is_array($potentialRes) && count($potentialRes) > 0) { + 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){ + #} Has results, tidy + return + foreach ( $potentialRes as $resDataLine ) { - // only coumns return. - $resArr = array(); - foreach ($onlyColumnsFieldArr as $colDBKey => $colStr){ + // using onlyColumns filter? + if ( $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 { - } else { - // tidy - $resArr = $this->tidy_quote($resDataLine,$withCustomFields); + $resArr = $this->tidy_quote( $resDataLine, $withCustomFields ); - } + } - if ($withLineItems){ + if ( $withLineItems ) { // add all line item lines - $resArr['lineitems'] = $this->DAL()->lineitems->getLineitems(array('associatedObjType'=>ZBS_TYPE_QUOTE,'associatedObjID'=>$resDataLine->ID,'perPage'=>1000,'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_LINEITEM))); - + $resArr['lineitems'] = $this->DAL()->lineitems->getLineitems( + array( + 'associatedObjType' => ZBS_TYPE_QUOTE, + 'associatedObjID' => $resDataLine->ID, + 'perPage' => 1000, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_LINEITEM ), + ) + ); + } - if ($withFiles){ + if ( $withFiles ) { - $resArr['files'] = zeroBSCRM_files_getFiles('quote',$resDataLine->ID); - - } + $resArr['files'] = zeroBSCRM_files_getFiles( 'quote', $resDataLine->ID ); - if ($withTags){ + } + + if ( $withTags ) { // add all tags lines - $resArr['tags'] = $this->DAL()->getTagsForObjID(array('objtypeid'=>ZBS_TYPE_QUOTE,'objid'=>$resDataLine->ID)); + $resArr['tags'] = $this->DAL()->getTagsForObjID( + array( + 'objtypeid' => ZBS_TYPE_QUOTE, + 'objid' => $resDataLine->ID, + ) + ); } - if ($withAssigned){ + if ( $withAssigned ) { - /* This is for MULTIPLE (e.g. multi contact/companies assigned to an inv) + /* + 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_QUOTE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + // add all assigned contacts/companies + $res['contacts'] = $this->DAL()->contacts->getContacts(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_QUOTE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); - $res['companies'] = $this->DAL()->companies->getCompanies(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_QUOTE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'perPage'=>-1, - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + $res['companies'] = $this->DAL()->companies->getCompanies(array( + 'hasObjTypeLinkedTo'=>ZBS_TYPE_QUOTE, + 'hasObjIDLinkedTo'=>$resDataLine->ID, + 'perPage'=>-1, + 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); - .. but we use 1:1, at least now: */ + .. but we use 1:1, at least now: */ - // add all assigned contacts/companies - $resArr['contact'] = $this->DAL()->contacts->getContacts(array( - 'hasObjTypeLinkedTo'=>ZBS_TYPE_QUOTE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT))); + // add all assigned contacts/companies + $resArr['contact'] = $this->DAL()->contacts->getContacts( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_QUOTE, + '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_QUOTE, - 'hasObjIDLinkedTo'=>$resDataLine->ID, - 'page' => 0, - 'perPage'=>1, // FORCES 1 - 'ignoreowner'=>zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY))); + $resArr['company'] = $this->DAL()->companies->getCompanies( + array( + 'hasObjTypeLinkedTo' => ZBS_TYPE_QUOTE, + 'hasObjIDLinkedTo' => $resDataLine->ID, + 'page' => 0, + 'perPage' => 1, // FORCES 1 + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); - - } + } - if ($suppressContent) unset($resArr['content']); + if ( $suppressContent ) { + unset( $resArr['content'] ); + } $res[] = $resArr; @@ -931,9 +1113,7 @@ public function getQuotes($args=array()){ } return $res; - } - - + } /** * Returns a count of quotes (owned) @@ -941,33 +1121,54 @@ public function getQuotes($args=array()){ * * @return int count */ - public function getQuoteCount($args=array()){ + public function getQuoteCount( $args = array() ) { #} ============ LOAD ARGS ============= $defaultArgs = array( // Search/Filtering (leave as false to ignore) - 'withStatus' => false, // will be str if used + 'withStatus' => false, // will be str if used // permissions - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_QUOTE), // this'll let you not-check the owner of obj + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_QUOTE ), // 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]; } } } + ); + 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('zbsq_status','=','%s',$withStatus); + if ( $withStatus !== false && ! empty( $withStatus ) ) { + $whereArr['status'] = array( 'zbsq_status', '=', '%s', $withStatus ); + } - return $this->DAL()->getFieldByWHERE(array( - 'objtype' => ZBS_TYPE_QUOTE, - 'colname' => 'COUNT(ID)', - 'where' => $whereArr, - 'ignoreowner' => $ignoreowner)); - + return $this->DAL()->getFieldByWHERE( + array( + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'COUNT(ID)', + 'where' => $whereArr, + 'ignoreowner' => $ignoreowner, + ) + ); } - /** + /** * adds or updates a quote object * * @param array $args Associative array of arguments @@ -975,405 +1176,440 @@ public function getQuoteCount($args=array()){ * * @return int line ID */ - public function addUpdateQuote($args=array()){ + public function addUpdateQuote( $args = array() ) { + + global $ZBSCRM_t, $wpdb, $zbs; - global $ZBSCRM_t,$wpdb,$zbs; - #} Retrieve any cf - $customFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_QUOTE)); - $addrCustomFields = $this->DAL()->getActiveCustomFields(array('objtypeid'=>ZBS_TYPE_ADDRESS)); + $customFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_QUOTE ) ); + $addrCustomFields = $this->DAL()->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) ); #} ============ LOAD ARGS ============= $defaultArgs = array( - 'id' => -1, - 'owner' => -1, + 'id' => -1, + 'owner' => -1, // fields (directly) - 'data' => array( - - 'id_override' => '', - 'title' => '', - 'currency' => '', - 'value' => '', - 'date' => '', - 'template' => '', - 'content' => '', - 'notes' => '', - 'send_attachments' => -1, - 'hash' => '', - 'lastviewed' => '', - 'viewed_count' => '', - 'accepted' => '', - 'acceptedsigned' => '', - 'acceptedip' => '', + 'data' => array( + + 'id_override' => '', + 'title' => '', + 'currency' => '', + 'value' => '', + 'date' => '', + 'template' => '', + 'content' => '', + 'notes' => '', + 'send_attachments' => -1, + 'hash' => '', + 'lastviewed' => '', + 'viewed_count' => '', + 'accepted' => '', + 'acceptedsigned' => '', + 'acceptedip' => '', // lineitems: - 'lineitems' => false, + '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 + // 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 + 'contacts' => false, // array of id's + 'companies' => false, // array of id's - // tags - 'tags' => -1, // pass an array of tag ids or tag strings - 'tag_mode' => 'replace', // replace|append|remove + // 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 :) + 'externalSources' => -1, // if this is an array(array('source'=>src,'uid'=>uid),multiple()) it'll add :) // allow this to be set for MS sync, Migrations etc. - 'created' => -1, - 'lastupdated' => '', + 'created' => -1, + 'lastupdated' => '', ), - 'limitedFields' => -1, // if this is set it OVERRIDES data (allowing you to set specific fields + leave rest in tact) + '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, + // this function as DAL1 func did. + 'extraMeta' => -1, 'automatorPassthrough' => -1, - 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newQuote (because is migrating, not creating new :) this was -1 before + 'silentInsert' => false, // this was for init Migration - it KILLS all IA for newQuote (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_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 ]; + } + } + } - ); 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){ + // 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]; + 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 zbsq_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){ + // this takes limited fields + checks through for custom fields present + // (either as key zbsq_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 ) ) { - // some weird case where getting empties, so added check - if (isset($field['key']) && !empty($field['key'])){ + // $customFieldKeys = array_keys($customFields); + $newLimitedFields = array(); - $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if ( str_starts_with( $field['key'], 'zbsq_' ) ) { - $dePrefixed = substr( $field['key'], strlen( 'zbsq_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + // cycle through + foreach ( $limitedFields as $field ) { - if (isset($customFields[$field['key']])){ + // some weird case where getting empties, so added check + if ( isset( $field['key'] ) && ! empty( $field['key'] ) ) { - // is custom, move to data - $data[$field['key']] = $field['val']; + $dePrefixed = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( str_starts_with( $field['key'], 'zbsq_' ) ) { + $dePrefixed = substr( $field['key'], strlen( 'zbsq_' ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - } 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); + // 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 (!user_can($owner,'admin_zerobs_usr')) $owner = -1; - - // if owner = -1, add current - if (!isset($owner) || $owner === -1) { $owner = zeroBSCRM_user(); } - - // if no date is passed, use current date - if ( empty( $data['date'] ) ) { - $data['date'] = time(); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable - } - if (is_array($limitedFields)){ + $id = (int) $id; - // 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; + // here we check that the potential owner CAN even own + if ( ! user_can( $owner, 'admin_zerobs_usr' ) ) { + $owner = -1; + } - } else { + // if owner = -1, add current + if ( ! isset( $owner ) || $owner === -1 ) { + $owner = zeroBSCRM_user(); + } + + // if no date is passed, use current date + if ( empty( $data['date'] ) ) { + $data['date'] = time(); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + } - // NORMAL, FULL UPDATE + 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 =========== + } + #} ========= / 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; + // 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_quote($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'=>'zbsq_x','val'=>y,'type'=>'%s')) + // get data to copy over (for now, this is required to remove 'fullname' etc.) + $dbData = $this->db_ready_quote( $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'=>'zbsq_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' => 'zbsq_'.$k, // we have to add zbsq_ here because translating from data -> limited fields - 'val' => $v, - 'type' => $this->getTypeStr('zbsq_'.$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' => 'zbsq_' . $k, // we have to add zbsq_ here because translating from data -> limited fields + 'val' => $v, + 'type' => $this->getTypeStr( 'zbsq_' . $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) =========== #} ========= BUILD DATA =========== - $update = false; $dataArr = array(); $typeArr = array(); - $was_accepted_before = $this->getQuoteAccepted( $id ); - - if (is_array($limitedFields)){ + $update = false; + $dataArr = array(); + $typeArr = array(); + $was_accepted_before = $this->getQuoteAccepted( $id ); - // LIMITED FIELDS - $update = true; + if ( is_array( $limitedFields ) ) { - // cycle through - foreach ($limitedFields as $field){ + // LIMITED FIELDS + $update = true; - // some weird case where getting empties, so added check - if (!empty($field['key'])){ - $dataArr[$field['key']] = $field['val']; - $typeArr[] = $field['type']; - } + // 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['zbsq_lastupdated'])){ $dataArr['zbsq_lastupdated'] = time(); $typeArr[] = '%d'; } - - } else { - - // FULL UPDATE/INSERT - - // contacts - avoid dupes - if (isset($data['contacts']) && is_array($data['contacts'])){ + // add update time + if ( ! isset( $dataArr['zbsq_lastupdated'] ) ) { + $dataArr['zbsq_lastupdated'] = time(); + $typeArr[] = '%d'; + } + } 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; } + } - // companies - avoid dupes - if (isset($data['companies']) && is_array($data['companies'])){ + // reset the main + if ( count( $coArr ) > 0 ) { + $data['contacts'] = $coArr; + } else { + $data['contacts'] = 'unset'; + } + unset( $coArr ); - $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); + // 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; } + } - // 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, - - - 'zbsq_id_override' => $data['id_override'], - 'zbsq_title' => $data['title'], - 'zbsq_currency' => $data['currency'], - 'zbsq_value' => $data['value'], - 'zbsq_date' => $data['date'], - 'zbsq_template' => $data['template'], - 'zbsq_content' => $data['content'], - 'zbsq_notes' => $data['notes'], - 'zbsq_send_attachments' => $data['send_attachments'], - 'zbsq_hash' => $data['hash'], - 'zbsq_lastviewed' => $data['lastviewed'], - 'zbsq_viewed_count' => $data['viewed_count'], - 'zbsq_accepted' => $data['accepted'], - 'zbsq_acceptedsigned' => $data['acceptedsigned'], - 'zbsq_acceptedip' => $data['acceptedip'], - 'zbsq_lastupdated' => time(), - - ); + // reset the main + if ( count( $coArr ) > 0 ) { + $data['companies'] = $coArr; + } else { + $data['companies'] = 'unset'; + } + unset( $coArr ); - $typeArr = array( // field data types - //'%d', // site - //'%d', // team - //'%d', // owner - - - '%s', - '%s', - '%s', - '%s', - '%d', - '%s', - '%s', - '%s', - '%d', // send_attachment - '%s', - '%d', - '%d', - '%d', - '%s', - '%s', - '%d', + } - ); + // 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, + + 'zbsq_id_override' => $data['id_override'], + 'zbsq_title' => $data['title'], + 'zbsq_currency' => $data['currency'], + 'zbsq_value' => $data['value'], + 'zbsq_date' => $data['date'], + 'zbsq_template' => $data['template'], + 'zbsq_content' => $data['content'], + 'zbsq_notes' => $data['notes'], + 'zbsq_send_attachments' => $data['send_attachments'], + 'zbsq_hash' => $data['hash'], + 'zbsq_lastviewed' => $data['lastviewed'], + 'zbsq_viewed_count' => $data['viewed_count'], + 'zbsq_accepted' => $data['accepted'], + 'zbsq_acceptedsigned' => $data['acceptedsigned'], + 'zbsq_acceptedip' => $data['acceptedip'], + 'zbsq_lastupdated' => time(), - if (!empty($id) && $id > 0){ + ); - // is update - $update = true; + $typeArr = array( // field data types + // '%d', // site + // '%d', // team + // '%d', // owner + + '%s', + '%s', + '%s', + '%s', + '%d', + '%s', + '%s', + '%s', + '%d', // send_attachment + '%s', + '%d', + '%d', + '%d', + '%s', + '%s', + '%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['zbsq_created'] = $data['created'];$typeArr[] = '%d'; - } else { - $dataArr['zbsq_created'] = time(); $typeArr[] = '%d'; - } + if ( ! empty( $id ) && $id > 0 ) { + // is update + $update = true; - // and on new inserts, if no hash passed, it gen's one - if (isset($dataArr['zbsq_hash']) && $dataArr['zbsq_hash'] == '') $dataArr['zbsq_hash'] = zeroBSCRM_generateHash(20); + } 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['zbsq_created'] = $data['created']; + $typeArr[] = '%d'; + } else { + $dataArr['zbsq_created'] = time(); + $typeArr[] = '%d'; } + // and on new inserts, if no hash passed, it gen's one + if ( isset( $dataArr['zbsq_hash'] ) && $dataArr['zbsq_hash'] == '' ) { + $dataArr['zbsq_hash'] = zeroBSCRM_generateHash( 20 ); + } } + } #} ========= / 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 - // #v3.1 - would make sense to unique/nonempty check just the limited fields. #gh-145 - if (!is_array($limitedFields)){ + // 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 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 ================ + #} ============================================================ - // 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 ( $update ) { - /* WH included this "for now" - status change for IA, not sure if used for this obj,? + /* + WH included this "for now" - status change for IA, not sure if used for this obj,? #} Check if obj exists (here) - for now just brutal update (will error when doesn't exist) $originalStatus = $this->getQuoteStatus($id); // log any change of status - if (isset($dataArr['zbsq_status']) && !empty($dataArr['zbsq_status']) && !empty($originalStatus) && $dataArr['zbsq_status'] != $originalStatus){ + if ( isset( $dataArr['zbsq_status']) && !empty( $dataArr['zbsq_status']) && !empty( $originalStatus) && $dataArr['zbsq_status'] != $originalStatus){ // status change $statusChange = array( @@ -1383,357 +1619,390 @@ public function addUpdateQuote($args=array()){ } */ - #} Attempt update - if ($wpdb->update( - $ZBSCRM_t['quotes'], - $dataArr, - array( // where - 'ID' => $id - ), - $typeArr, - array( // where data types - '%d' - )) !== false){ + #} Attempt update + if ( $wpdb->update( + $ZBSCRM_t['quotes'], + $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 ==== - // 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_QUOTE)); + // 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_QUOTE, - 'linkedObjID' => $id, - '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' => $id, + 'objType' => ZBS_TYPE_QUOTE, + ) + ); - } else { + // addupdate each + foreach ( $data['lineitems'] as $lineitem ) { - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$id,'objType'=>ZBS_TYPE_QUOTE)); + // 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_QUOTE, + 'linkedObjID' => $id, + 'data' => $lineitem, + ) + ); - } + } + } else { + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $id, + 'objType' => ZBS_TYPE_QUOTE, + ) + ); - } + } + } - // / Line Items ==== + // / Line Items ==== + + // OBJ LINKS - to contacts/companies + $this->addUpdateObjectLinks( $id, $data['contacts'], ZBS_TYPE_CONTACT ); // 13567 + $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'], + ); + + // tags + if ( isset( $data['tags'] ) && is_array( $data['tags'] ) ) { + + $this->addUpdateQuoteTags( + array( + 'id' => $id, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], + ) + ); + } - // OBJ LINKS - to contacts/companies - $this->addUpdateObjectLinks($id,$data['contacts'],ZBS_TYPE_CONTACT); ///13567 - $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']); + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $id, + 'obj_type_id' => ZBS_TYPE_QUOTE, + 'external_sources' => isset( $data['externalSources'] ) ? $data['externalSources'] : array(), + ) + ); // for IA below - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + // Custom fields? - $this->addUpdateQuoteTags( - array( - 'id' => $id, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + #} Cycle through + add/update if set + if ( is_array( $customFields ) ) { + foreach ( $customFields as $cK => $cF ) { - } + // any? + if ( isset( $data[ $cK ] ) ) { - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + // add update + $cfID = $this->DAL()->addUpdateCustomField( array( - 'obj_id' => $id, - 'obj_type_id' => ZBS_TYPE_QUOTE, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), + 'data' => array( + 'objtype' => ZBS_TYPE_QUOTE, + 'objid' => $id, + 'objkey' => $cK, + 'objval' => $data[ $cK ], + ), ) - ); // 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_QUOTE, - '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 WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + // / Custom Fields - $confirmedExtraMeta = array(); + } // / if $data - foreach ($extraMeta as $k => $v){ + #} 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 won't fix stupid keys, just catch basic fails... - $cleanKey = strtolower(str_replace(' ','_',$k)); + $confirmedExtraMeta = array(); - #} Brutal update - //update_post_meta($postID, 'zbs_customer_extra_'.$cleanKey, $v); - $this->DAL()->updateMeta(ZBS_TYPE_QUOTE,$id,'extra_'.$cleanKey,$v); + foreach ( $extraMeta as $k => $v ) { - #} Add it to this, which passes to IA - $confirmedExtraMeta[$cleanKey] = $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_QUOTE, $id, 'extra_' . $cleanKey, $v ); - } + #} Add it to this, which passes to IA + $confirmedExtraMeta[ $cleanKey ] = $v; + } + } - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // UPDATING CONTACT - if (!$silentInsert){ - - - // IA General quote update (2.87+) - zeroBSCRM_FireInternalAutomator('quote.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 #} This is the "extraMeta" passed (as saved) - )); - - // First check if the quote status is new before fire the event - if ( empty( $was_accepted_before ) && $data['accepted'] ) { - - // IA quote.accepted - zeroBSCRM_FireInternalAutomator('quote.accepted', array( - 'id' => $id, - 'data' => $data, - 'againstids' => false, - 'extsource' => false, - 'automatorpassthrough' => false, - 'extraMeta' => $confirmedExtraMeta, - )); - } + #} INTERNAL AUTOMATOR + #} & + #} FALLBACKS + // UPDATING CONTACT + if ( ! $silentInsert ) { - } + // IA General quote update (2.87+) + zeroBSCRM_FireInternalAutomator( + 'quote.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, #} This is the "extraMeta" passed (as saved) + ) + ); + + // First check if the quote status is new before fire the event + if ( empty( $was_accepted_before ) && $data['accepted'] ) { + + // IA quote.accepted + zeroBSCRM_FireInternalAutomator( + 'quote.accepted', + array( + 'id' => $id, + 'data' => $data, + 'againstids' => false, + 'extsource' => false, + 'automatorpassthrough' => false, + 'extraMeta' => $confirmedExtraMeta, + ) + ); + } + } - - // Successfully updated - Return id - return $id; + // Successfully updated - Return id + return $id; - } else { - - $msg = __('DB Update Failed','zero-bs-crm'); - $zbs->DAL->addError(302,$this->objectType,$msg,$dataArr); + } else { - // FAILED update - return false; + $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['quotes'], - $dataArr, - $typeArr ) > 0){ - - #} Successfully inserted, lets return new ID - $newID = $wpdb->insert_id; - - // Line Items ==== - - // line item work - if (isset($data['lineitems']) && is_array($data['lineitems'])){ + #} No ID - must be an INSERT + if ( $wpdb->insert( + $ZBSCRM_t['quotes'], + $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_QUOTE)); + // 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_QUOTE, - '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_QUOTE, + ) + ); - } else { + // addupdate each + foreach ( $data['lineitems'] as $lineitem ) { - // delete all lineitems - $this->DAL()->lineitems->deleteLineItemsForObject(array('objID'=>$newID,'objType'=>ZBS_TYPE_QUOTE)); + // 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_QUOTE, + 'linkedObjID' => $newID, + 'data' => $lineitem, + ) + ); } + } else { + // delete all lineitems + $this->DAL()->lineitems->deleteLineItemsForObject( + array( + 'objID' => $newID, + 'objType' => ZBS_TYPE_QUOTE, + ) + ); } + } - // / 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']); - - - // tags - if (isset($data['tags']) && is_array($data['tags'])) { + // / Line Items ==== - $this->addUpdateQuoteTags( - array( - 'id' => $newID, - 'tag_input' => $data['tags'], - 'mode' => $data['tag_mode'] - ) - ); + // 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'] ) ) { - // externalSources - $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + $this->addUpdateQuoteTags( array( - 'obj_id' => $newID, - 'obj_type_id' => ZBS_TYPE_QUOTE, - 'external_sources' => isset($data['externalSources']) ? $data['externalSources'] : array(), + 'id' => $newID, + 'tag_input' => $data['tags'], + 'mode' => $data['tag_mode'], ) - ); // 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_QUOTE, - 'objid' => $newID, - 'objkey' => $cK, - 'objval' => $data[$cK] - ))); + } - } + // externalSources + $approvedExternalSource = $this->DAL()->addUpdateExternalSources( + array( + 'obj_id' => $newID, + 'obj_type_id' => ZBS_TYPE_QUOTE, + '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_QUOTE, + '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 WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + // / Custom Fields - $confirmedExtraMeta = array(); + #} 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 ($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_QUOTE,$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_QUOTE, $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( + 'quote.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) + ) + ); - #} INTERNAL AUTOMATOR - #} & - #} FALLBACKS - // NEW CONTACT - if (!$silentInsert){ - - #} Add to automator - zeroBSCRM_FireInternalAutomator('quote.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) - )); + } - } - - 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; - } - /** + /** * adds or updates a quote's tags * ... this is really just a wrapper for addUpdateObjectTags * @@ -1742,173 +2011,238 @@ public function addUpdateQuote($args=array()){ * * @return int line ID */ - public function addUpdateQuoteTags($args=array()){ + public function addUpdateQuoteTags( $args = array() ) { - global $ZBSCRM_t,$wpdb; + global $ZBSCRM_t, $wpdb; #} ============ LOAD ARGS ============= $defaultArgs = array( - 'id' => -1, + 'id' => -1, - // generic pass-through (array of tag strings or tag IDs): - 'tag_input' => -1, + // generic pass-through (array of tag strings or tag IDs): + 'tag_input' => -1, - // or either specific: - 'tagIDs' => -1, - 'tags' => -1, + // or either specific: + 'tagIDs' => -1, + 'tags' => -1, - 'mode' => 'append' + '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]; } } } + ); + 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 id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } #} ========= / CHECK FIELDS =========== - return $this->DAL()->addUpdateObjectTags( - array( - 'objtype' => ZBS_TYPE_QUOTE, - 'objid' => $id, - 'tag_input' => $tag_input, - 'tags' => $tags, - 'tagIDs' => $tagIDs, - 'mode' => $mode - ) - ); - + return $this->DAL()->addUpdateObjectTags( + array( + 'objtype' => ZBS_TYPE_QUOTE, + 'objid' => $id, + 'tag_input' => $tag_input, + 'tags' => $tags, + 'tagIDs' => $tagIDs, + 'mode' => $mode, + ) + ); } - /** - * updates template for a quote - * - * @param int id quote ID - * @param int template ID - * - * @return bool - */ - public function setQuoteTemplate($id=-1,$template=-1){ - - global $zbs; - - $id = (int)$id; - - if ($id > 0){ + /** + * updates template for a quote + * + * @param int id quote ID + * @param int template ID + * + * @return bool + */ + public function setQuoteTemplate( $id = -1, $template = -1 ) { - return $this->addUpdateQuote(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbsq_template','val' => $template,'type' => '%d') - ))); + global $zbs; - } + $id = (int) $id; - return false; - - } + if ( $id > 0 ) { + return $this->addUpdateQuote( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsq_template', + 'val' => $template, + 'type' => '%d', + ), + ), + ) + ); - /** - * accepts/unaccepts a quote - * ... this is really just a wrapper for addUpdateQuote - * ... and replaces zeroBS_markQuoteAccepted + zeroBS_markQuoteUnAccepted - * - * @param array $args Associative array of arguments - * id (if update), owner, data (array of field data) - * - * @return int line ID - */ - public function addUpdateQuoteAccepted($args=array()){ + } - global $ZBSCRM_t,$wpdb; + return false; + } - #} ============ LOAD ARGS ============= - $defaultArgs = array( + /** + * accepts/unaccepts a quote + * ... this is really just a wrapper for addUpdateQuote + * ... and replaces zeroBS_markQuoteAccepted + zeroBS_markQuoteUnAccepted + * + * @param array $args Associative array of arguments + * id (if update), owner, data (array of field data) + * + * @return int line ID + */ + public function addUpdateQuoteAccepted( $args = array() ) { - 'id' => -1, - 'accepted' => -1, - 'signedby' => '', - 'ip' => '' + 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, + 'accepted' => -1, + 'signedby' => '', + 'ip' => '', - // 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 ============ - // WPID may be -1 (NULL) - // -1 does okay here if ($WPID == -1) $WPID = ''; + #} ========== CHECK FIELDS ============ - #} ========= / CHECK FIELDS =========== + // check id + $id = (int) $id; + if ( empty( $id ) || $id <= 0 ) { + return false; + } + // WPID may be -1 (NULL) + // -1 does okay here if ($WPID == -1) $WPID = ''; - #} Enact - $r = $this->addUpdateQuote(array( - 'id' => $id, - 'limitedFields' =>array( - array('key'=>'zbsq_accepted','val'=>$accepted,'type'=>'%d'), - array('key'=>'zbsq_acceptedsigned','val'=>$signedby,'type'=>'%s'), - array('key'=>'zbsq_acceptedip','val'=>$ip,'type'=>'%s') - ))); + #} ========= / CHECK FIELDS =========== + #} Enact + $r = $this->addUpdateQuote( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsq_accepted', + 'val' => $accepted, + 'type' => '%d', + ), + array( + 'key' => 'zbsq_acceptedsigned', + 'val' => $signedby, + 'type' => '%s', + ), + array( + 'key' => 'zbsq_acceptedip', + 'val' => $ip, + 'type' => '%s', + ), + ), + ) + ); - // if quote was accepted, run internal automator quote.accepted - if ( $accepted ){ + // if quote was accepted, run internal automator quote.accepted + if ( $accepted ) { // fire automator - zeroBSCRM_FireInternalAutomator('quote.accepted',array( - 'id'=>$id, - 'data'=>array('signed'=>$signedby,'ip'=>$ip), - 'againstids'=>false, - 'extsource'=>false, - 'automatorpassthrough'=>false, - 'extraMeta'=>false - )); - - } - - - return $r; - - } + zeroBSCRM_FireInternalAutomator( + 'quote.accepted', + array( + 'id' => $id, + 'data' => array( + 'signed' => $signedby, + 'ip' => $ip, + ), + 'againstids' => false, + 'extsource' => false, + 'automatorpassthrough' => false, + 'extraMeta' => false, + ) + ); - /** - * updates status for an quote (no blanks allowed) - * - * @param int id quote ID - * @param string quote Status - * - * @return bool - */ - public function setQuoteStatus($id=-1,$status=-1){ + } - global $zbs; + return $r; + } - $id = (int)$id; + /** + * updates status for an quote (no blanks allowed) + * + * @param int id quote ID + * @param string quote Status + * + * @return bool + */ + public function setQuoteStatus( $id = -1, $status = -1 ) { - if ($id > 0 && !empty($status) && $status !== -1){ + global $zbs; - return $this->addUpdateQuote(array( - 'id'=>$id, - 'limitedFields'=>array( - array('key'=>'zbsq_status','val' => $status,'type' => '%s') - ))); + $id = (int) $id; - } + if ( $id > 0 && ! empty( $status ) && $status !== -1 ) { - return false; - - } + return $this->addUpdateQuote( + array( + 'id' => $id, + 'limitedFields' => array( + array( + 'key' => 'zbsq_status', + 'val' => $status, + 'type' => '%s', + ), + ), + ) + ); + } + return false; + } - /** + /** * deletes a quote object * * @param array $args Associative array of arguments @@ -1916,58 +2250,81 @@ public function setQuoteStatus($id=-1,$status=-1){ * * @return int success; */ - public function deleteQuote($args=array()){ + public function deleteQuote( $args = array() ) { - global $ZBSCRM_t,$wpdb,$zbs; + global $ZBSCRM_t, $wpdb, $zbs; #} ============ LOAD ARGS ============= $defaultArgs = array( - 'id' => -1, - 'saveOrphans' => false + '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]; } } } + ); + 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) { - + $id = (int) $id; + if ( ! empty( $id ) && $id > 0 ) { + // delete orphans? - if ($saveOrphans === false){ + if ( $saveOrphans === false ) { // delete any tag links - $this->DAL()->deleteTagObjLinks(array( + $this->DAL()->deleteTagObjLinks( + array( - 'objtype' => ZBS_TYPE_QUOTE, - 'objid' => $id - )); + 'objtype' => ZBS_TYPE_QUOTE, + 'objid' => $id, + ) + ); - // delete any external source information - $this->DAL()->delete_external_sources( array( + // delete any external source information + $this->DAL()->delete_external_sources( + array( - 'obj_type' => ZBS_TYPE_FORM, - 'obj_id' => $id, - 'obj_source' => 'all', + 'obj_type' => ZBS_TYPE_FORM, + 'obj_id' => $id, + 'obj_source' => 'all', - )); + ) + ); } - $del = zeroBSCRM_db2_deleteGeneric($id,'quotes'); + $del = zeroBSCRM_db2_deleteGeneric( $id, 'quotes' ); - #} Add to automator - zeroBSCRM_FireInternalAutomator('quote.delete',array( - 'id'=>$id, - 'saveOrphans'=>$saveOrphans - )); + #} Add to automator + zeroBSCRM_FireInternalAutomator( + 'quote.delete', + array( + 'id' => $id, + 'saveOrphans' => $saveOrphans, + ) + ); - return $del; + return $del; } return false; - } /** @@ -1979,58 +2336,59 @@ public function deleteQuote($args=array()){ */ public function tidy_quote( $obj = false, $withCustomFields = false ) { // phpcs:ignore - $res = false; + $res = false; - if (isset($obj->ID)){ - $res = 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, + /* + `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->zbsq_id_override); - $res['title'] = $this->stripSlashes($obj->zbsq_title); - $res['currency'] = $this->stripSlashes($obj->zbsq_currency); - $res['value'] = $this->stripSlashes($obj->zbsq_value); - $res['date'] = (int)$obj->zbsq_date; - $res['date_date'] = (isset($obj->zbsq_date) && $obj->zbsq_date > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsq_date,false,true) : false; - $res['template'] = (int)$this->stripSlashes($obj->zbsq_template); - $res['content'] = $this->stripSlashes($obj->zbsq_content); - $res['notes'] = $this->stripSlashes($obj->zbsq_notes); - $res['send_attachments'] = (bool)$obj->zbsq_send_attachments; - $res['hash'] = $this->stripSlashes($obj->zbsq_hash); - $res['lastviewed'] = (int)$obj->zbsq_lastviewed; - $res['lastviewed_date'] = (isset($obj->zbsq_lastviewed) && $obj->zbsq_lastviewed > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsq_lastviewed,false,true) : false; - $res['viewed_count'] = (int)$obj->zbsq_viewed_count; - $res['accepted'] = (int)$obj->zbsq_accepted; - $res['accepted_date'] = (isset($obj->zbsq_accepted) && $obj->zbsq_accepted > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsq_accepted,false,true) : false; - $res['acceptedsigned'] = (int)$obj->zbsq_accepted; - $res['acceptedip'] = (int)$obj->zbsq_accepted; - $res['created'] = (int)$obj->zbsq_created; - $res['created_date'] = (isset($obj->zbsq_created) && $obj->zbsq_created > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsq_created,false,true) : false; - $res['lastupdated'] = (int)$obj->zbsq_lastupdated; - $res['lastupdated_date'] = (isset($obj->zbsq_lastupdated) && $obj->zbsq_lastupdated > 0) ? zeroBSCRM_date_i18n(-1,$obj->zbsq_lastupdated,false,true) : false; + + $res['id_override'] = $this->stripSlashes( $obj->zbsq_id_override ); + $res['title'] = $this->stripSlashes( $obj->zbsq_title ); + $res['currency'] = $this->stripSlashes( $obj->zbsq_currency ); + $res['value'] = $this->stripSlashes( $obj->zbsq_value ); + $res['date'] = (int) $obj->zbsq_date; + $res['date_date'] = ( isset( $obj->zbsq_date ) && $obj->zbsq_date > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsq_date, false, true ) : false; + $res['template'] = (int) $this->stripSlashes( $obj->zbsq_template ); + $res['content'] = $this->stripSlashes( $obj->zbsq_content ); + $res['notes'] = $this->stripSlashes( $obj->zbsq_notes ); + $res['send_attachments'] = (bool) $obj->zbsq_send_attachments; + $res['hash'] = $this->stripSlashes( $obj->zbsq_hash ); + $res['lastviewed'] = (int) $obj->zbsq_lastviewed; + $res['lastviewed_date'] = ( isset( $obj->zbsq_lastviewed ) && $obj->zbsq_lastviewed > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsq_lastviewed, false, true ) : false; + $res['viewed_count'] = (int) $obj->zbsq_viewed_count; + $res['accepted'] = (int) $obj->zbsq_accepted; + $res['accepted_date'] = ( isset( $obj->zbsq_accepted ) && $obj->zbsq_accepted > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsq_accepted, false, true ) : false; + $res['acceptedsigned'] = (int) $obj->zbsq_accepted; + $res['acceptedip'] = (int) $obj->zbsq_accepted; + $res['created'] = (int) $obj->zbsq_created; + $res['created_date'] = ( isset( $obj->zbsq_created ) && $obj->zbsq_created > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsq_created, false, true ) : false; + $res['lastupdated'] = (int) $obj->zbsq_lastupdated; + $res['lastupdated_date'] = ( isset( $obj->zbsq_lastupdated ) && $obj->zbsq_lastupdated > 0 ) ? zeroBSCRM_date_i18n( -1, $obj->zbsq_lastupdated, false, true ) : false; // determine status :) $res['status'] = -1; // not yet pub - if (isset($res['template']) && $res['template'] > 0) $res['status'] = -2; // published not accepted - if (isset($res['accepted']) && $res['accepted'] > 0) $res['status'] = 1; // accepted - - // custom fields - tidy any that are present: - if ($withCustomFields) $res = $this->tidyAddCustomFields(ZBS_TYPE_QUOTE,$obj,$res,false); - - } + if ( isset( $res['template'] ) && $res['template'] > 0 ) { + $res['status'] = -2; // published not accepted + } + if ( isset( $res['accepted'] ) && $res['accepted'] > 0 ) { + $res['status'] = 1; // accepted + } + // custom fields - tidy any that are present: + if ( $withCustomFields ) { + $res = $this->tidyAddCustomFields( ZBS_TYPE_QUOTE, $obj, $res, false ); + } + } return $res; - - } - /** * Wrapper, use $this->getQuoteMeta($contactID,$key) for easy retrieval of singular quote * Simplifies $this->getMeta @@ -2041,22 +2399,24 @@ public function tidy_quote( $obj = false, $withCustomFields = false ) { // phpcs * * @return array quote meta result */ - public function getQuoteMeta($id=-1,$key='',$default=false){ + public function getQuoteMeta( $id = -1, $key = '', $default = false ) { global $zbs; - if (!empty($key)){ + if ( ! empty( $key ) ) { - return $this->DAL()->getMeta(array( + return $this->DAL()->getMeta( + array( - 'objtype' => ZBS_TYPE_QUOTE, - 'objid' => $id, - 'key' => $key, - 'fullDetails' => false, - 'default' => $default, - 'ignoreowner' => true // for now !! + 'objtype' => ZBS_TYPE_QUOTE, + 'objid' => $id, + 'key' => $key, + 'fullDetails' => false, + 'default' => $default, + 'ignoreowner' => true, // for now !! - )); + ) + ); } @@ -2070,24 +2430,26 @@ public function getQuoteMeta($id=-1,$key='',$default=false){ * * @return int quote owner id */ - public function getQuoteContent($id=-1){ + public function getQuoteContent( $id = -1 ) { global $zbs; - $id = (int)$id; + $id = (int) $id; - if ($id > 0){ + if ( $id > 0 ) { - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_QUOTE, - 'colname' => 'zbsq_content', - 'ignoreowner'=>true)); + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'zbsq_content', + 'ignoreowner' => true, + ) + ); } return false; - } /** @@ -2097,27 +2459,28 @@ public function getQuoteContent($id=-1){ * * @return int quote template ID, or 0 */ - public function getQuoteTemplateID($id=-1){ + public function getQuoteTemplateID( $id = -1 ) { global $zbs; - $id = (int)$id; + $id = (int) $id; - if ($id > 0){ + if ( $id > 0 ) { - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_QUOTE, - 'colname' => 'zbsq_template', - 'ignoreowner'=>true)); + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'zbsq_template', + 'ignoreowner' => true, + ) + ); } return false; - } - /** * Returns quote accepted UTC time, if accepted * @@ -2125,24 +2488,26 @@ public function getQuoteTemplateID($id=-1){ * * @return int UTC accepted, or 0 */ - public function getQuoteAcceptedTime($id=-1){ + public function getQuoteAcceptedTime( $id = -1 ) { global $zbs; - $id = (int)$id; + $id = (int) $id; - if ($id > 0){ + if ( $id > 0 ) { - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_QUOTE, - 'colname' => 'zbsq_accepted', - 'ignoreowner'=>true)); + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'zbsq_accepted', + 'ignoreowner' => true, + ) + ); } return false; - } /** @@ -2152,40 +2517,48 @@ public function getQuoteAcceptedTime($id=-1){ * * @return array (Accepted deets) */ - public function getQuoteAccepted($id=-1){ + public function getQuoteAccepted( $id = -1 ) { global $zbs; - $id = (int)$id; + $id = (int) $id; - if ($id > 0){ + if ( $id > 0 ) { $ret = array( - 'accepted' => $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_QUOTE, - 'colname' => 'zbsq_accepted', - 'ignoreowner'=>true)), - - 'acceptedsigned' => $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_QUOTE, - 'colname' => 'zbsq_acceptedsigned', - 'ignoreowner'=>true)), - - 'acceptedip' => $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_QUOTE, - 'colname' => 'zbsq_acceptedip', - 'ignoreowner'=>true)) + 'accepted' => $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'zbsq_accepted', + 'ignoreowner' => true, + ) + ), + + 'acceptedsigned' => $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'zbsq_acceptedsigned', + 'ignoreowner' => true, + ) + ), + + 'acceptedip' => $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'zbsq_acceptedip', + 'ignoreowner' => true, + ) + ), ); } return false; - } /** @@ -2195,24 +2568,26 @@ public function getQuoteAccepted($id=-1){ * * @return int quote owner id */ - public function getQuoteOwner($id=-1){ + public function getQuoteOwner( $id = -1 ) { global $zbs; - $id = (int)$id; + $id = (int) $id; - if ($id > 0){ + if ( $id > 0 ) { - return $this->DAL()->getFieldByID(array( - 'id' => $id, - 'objtype' => ZBS_TYPE_QUOTE, - 'colname' => 'zbs_owner', - 'ignoreowner'=>true)); + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'zbs_owner', + 'ignoreowner' => true, + ) + ); } return false; - } /** @@ -2222,61 +2597,65 @@ public function getQuoteOwner($id=-1){ * * @return int quote contact id */ - public function getQuoteContactID($id=-1){ + public function getQuoteContactID( $id = -1 ) { global $zbs; - $id = (int)$id; - - if ($id > 0){ + $id = (int) $id; - $contacts = $this->DAL()->getObjsLinkedToObj(array( + if ( $id > 0 ) { - 'objtypefrom' => ZBS_TYPE_QUOTE, - 'objtypeto' => ZBS_TYPE_CONTACT, - 'objfromid' => $id, - 'count' => false, - )); + $contacts = $this->DAL()->getObjsLinkedToObj( + array( - if (is_array($contacts)) foreach ($contacts as $c){ + 'objtypefrom' => ZBS_TYPE_QUOTE, + 'objtypeto' => ZBS_TYPE_CONTACT, + 'objfromid' => $id, + 'count' => false, + ) + ); - // first - return $c['id']; + if ( is_array( $contacts ) ) { + foreach ( $contacts as $c ) { - } + // first + return $c['id']; + } + } } return false; - } - /** - * Returns an hash against a quote - * - * @param int $id quote ID. - * - * @return string quote hash string - */ - public function getQuoteHash($id=-1){ + /** + * Returns an hash against a quote + * + * @param int $id quote ID. + * + * @return string quote hash string + */ + public function getQuoteHash( $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_QUOTE, - 'colname' => 'zbsq_hash', - 'ignoreowner'=>true)); + return $this->DAL()->getFieldByID( + array( + 'id' => $id, + 'objtype' => ZBS_TYPE_QUOTE, + 'colname' => 'zbsq_hash', + 'ignoreowner' => true, + ) + ); - } + } - return false; - - } + return false; + } /** * remove any non-db fields from the object @@ -2288,87 +2667,81 @@ public function getQuoteHash($id=-1){ * * @return array (db ready arr) */ - private function db_ready_quote($obj=false){ + private function db_ready_quote( $obj = false ) { // use the generic? (override here if necessary) - return $this->db_ready_obj($obj); - + 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( $quote = 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($quote=false,$columnsRequired=array()){ - - if (is_array($quote) && isset($quote['id'])){ + if ( is_array( $quote ) && isset( $quote['id'] ) ) { $resArr = $quote; - if (isset($quote['id_override']) && $quote['id_override'] !== null) + if ( isset( $quote['id_override'] ) && $quote['id_override'] !== null ) { $resArr['zbsid'] = $quote['id_override']; - else + } else { $resArr['zbsid'] = $quote['id']; + } #} Custom columns - #} Status - $resArr['statusint'] = -2; // def - - // determine status - this is now done in tidy_quote - if (isset($quote['status'])) $resArr['statusint'] = $quote['status']; - - if ($resArr['statusint'] == -2){ + #} Status + $resArr['statusint'] = -2; // def - #} is published - $resArr['status'] = ''.__('Not accepted yet',"zero-bs-crm").''; - - } else if ($resArr['statusint'] == -1){ + // determine status - this is now done in tidy_quote + if ( isset( $quote['status'] ) ) { + $resArr['statusint'] = $quote['status']; + } - #} not yet published - $resArr['status'] = ''.__('Draft',"zero-bs-crm").''; + if ( $resArr['statusint'] == -2 ) { + #} is published + $resArr['status'] = '' . __( 'Not accepted yet', 'zero-bs-crm' ) . ''; - } else { + } elseif ( $resArr['statusint'] == -1 ) { - #} Accepted - $resArr['status'] = ''.__('Accepted',"zero-bs-crm").' ' . date(zeroBSCRM_getDateFormat(),$quote['accepted']) . ''; + #} not yet published + $resArr['status'] = '' . __( 'Draft', 'zero-bs-crm' ) . ''; - } + } else { + #} Accepted + $resArr['status'] = '' . __( 'Accepted', 'zero-bs-crm' ) . ' ' . date( zeroBSCRM_getDateFormat(), $quote['accepted'] ) . ''; - #} customer - if (in_array('customer', $columnsRequired)){ + } - #} Convert $contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer - $resArr['customer'] = zeroBSCRM_getSimplyFormattedContact($quote['contact'],(in_array('assignedobj', $columnsRequired))); + #} customer + if ( in_array( 'customer', $columnsRequired ) ) { - #} Convert $contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer - // not yet. $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( $quote['contact'], ( in_array( 'assignedobj', $columnsRequired ) ) ); + #} Convert $contact arr into list-view-digestable 'customer'// & unset contact for leaner data transfer + // not yet. $resArr['company'] = zeroBSCRM_getSimplyFormattedCompany($transaction['company'],(in_array('assignedobj', $columnsRequired))); - } + } // let it use proper obj. - //$resArr['added'] = $quote['created_date']; + // $resArr['added'] = $quote['created_date']; // prev was 'val' - $resArr['value'] = zeroBSCRM_formatCurrency($resArr['value']); - - - return $resArr; + $resArr['value'] = zeroBSCRM_formatCurrency( $resArr['value'] ); - } + return $resArr; - return false; - - } + } + return false; + } // =========== / QUOTE ======================================================= // =============================================================================== diff --git a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Segments.php b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Segments.php index db6cf9ef8641..5fd788c61bd9 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Segments.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Segments.php @@ -1,5 +1,5 @@ -> 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 +811,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 +1791,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..db491bc4207d 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Transactions.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.Obj.Transactions.php @@ -1,5 +1,5 @@ -> 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 +274,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 +320,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 +508,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 +847,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 +901,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 +914,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 +1037,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 +1056,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 +1073,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 +1093,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 +1146,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..1e86422c22cf 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.ObjectLayer.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.ObjectLayer.php @@ -1,5 +1,5 @@ -> 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 +63,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 +803,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 +1400,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..6fb615df30fd 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DAL3.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DAL3.php @@ -1,5 +1,5 @@ -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 +85,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 +195,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 +265,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 +275,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 +543,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 +743,1216 @@ 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,1299 @@ 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 +8558,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 +8664,296 @@ 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 +8975,11 @@ 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..dcba2b1b0327 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DashboardBoxes.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DashboardBoxes.php @@ -1,5 +1,5 @@ -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..4df84200c60b 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.DataIOValidation.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.DataIOValidation.php @@ -1,5 +1,5 @@ - - 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 +164,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 +223,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 +314,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..e9419c53d935 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Database.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Database.php @@ -1,5 +1,5 @@ -last_error)) $zbsDB_lastError = $wpdb->last_error; - $zbsDB_creationErrors = array(); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsc_status` VARCHAR(100) NULL, - `zbsc_email` VARCHAR(200) NULL, - `zbsc_prefix` VARCHAR(30) NULL, - `zbsc_fname` VARCHAR(100) NULL, - `zbsc_lname` VARCHAR(100) NULL, - `zbsc_addr1` VARCHAR(200) NULL, - `zbsc_addr2` VARCHAR(200) NULL, - `zbsc_city` VARCHAR(200) NULL, - `zbsc_county` VARCHAR(200) NULL, - `zbsc_country` VARCHAR(200) NULL, - `zbsc_postcode` VARCHAR(50) NULL, - `zbsc_secaddr1` VARCHAR(200) NULL, - `zbsc_secaddr2` VARCHAR(200) NULL, - `zbsc_seccity` VARCHAR(200) NULL, - `zbsc_seccounty` VARCHAR(200) NULL, - `zbsc_seccountry` VARCHAR(200) NULL, - `zbsc_secpostcode` VARCHAR(50) NULL, - `zbsc_hometel` VARCHAR(40) NULL, - `zbsc_worktel` VARCHAR(40) NULL, - `zbsc_mobtel` VARCHAR(40) NULL, - `zbsc_wpid` INT NULL DEFAULT NULL, - `zbsc_avatar` VARCHAR(300) NULL, - `zbsc_tw` VARCHAR(100) NULL, - `zbsc_li` VARCHAR(300) NULL, - `zbsc_fb` VARCHAR(200) NULL, - `zbsc_created` INT(14) NOT NULL, - `zbsc_lastupdated` INT(14) NOT NULL, - `zbsc_lastcontacted` INT(14) NULL DEFAULT NULL, - 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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbscf_objtype` INT(4) NOT NULL, - `zbscf_objid` INT(32) NOT NULL, - `zbscf_objkey` VARCHAR(100) NOT NULL, - `zbscf_objval` VARCHAR(2000) NULL DEFAULT NULL, - `zbscf_created` INT(14) NOT NULL, - `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); - - - // 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, - `zbs_owner` INT NOT NULL, - `zbstag_objtype` INT NOT NULL, - `zbstag_name` VARCHAR(200) NOT NULL, - `zbstag_slug` VARCHAR(200) NOT NULL, - `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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbstl_objtype` INT(4) NOT NULL, - `zbstl_objid` INT NOT NULL, - `zbstl_tagid` INT NOT NULL, - PRIMARY KEY (`ID`), - 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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsset_key` VARCHAR(100) NOT NULL DEFAULT -1, - `zbsset_val` LONGTEXT NULL DEFAULT NULL, - `zbsset_created` INT(14) NOT NULL, - `zbsset_lastupdated` INT(14) NOT NULL, - PRIMARY KEY (`ID`), - INDEX `zbsset_key` (`zbsset_key`), - INDEX (`zbs_owner`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsm_objtype` INT NOT NULL, - `zbsm_objid` INT NOT NULL, - `zbsm_key` VARCHAR(255) NOT NULL, - `zbsm_val` LONGTEXT NULL DEFAULT NULL, - `zbsm_created` INT(14) NOT NULL, - `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); - - #} 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, - `zbs_owner` INT NOT NULL, - `zbsseg_name` VARCHAR(120) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL, - `zbsseg_slug` VARCHAR(45) NOT NULL, - `zbsseg_matchtype` VARCHAR(10) NOT NULL, - `zbsseg_created` INT(14) NOT NULL, - `zbsseg_lastupdated` INT(14) NOT NULL, - `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); - - // 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, - `zbscondition_op` VARCHAR(50) NULL, - `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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsadmlog_status` INT(3) NOT NULL, - `zbsadmlog_cat` VARCHAR(20) NULL DEFAULT NULL, - `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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbstemphash_status` INT NULL DEFAULT -1, - `zbstemphash_objtype` VARCHAR(50) NOT NULL, - `zbstemphash_objid` INT NULL DEFAULT NULL, - `zbstemphash_objhash` VARCHAR(256) NULL DEFAULT NULL, - `zbstemphash_created` INT(14) NOT NULL, - `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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsol_objtype_from` INT(4) NOT NULL, - `zbsol_objtype_to` INT(4) NOT NULL, - `zbsol_objid_from` INT NOT NULL, - `zbsol_objid_to` INT NOT NULL, - PRIMARY KEY (`ID`), - INDEX (`zbsol_objid_from`), - INDEX (`zbsol_objid_to`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - #} 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, - `aka_alias` VARCHAR(200) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL, - `aka_created` INT(14) NULL, - `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'] ."( - `ID` INT NOT NULL AUTO_INCREMENT, - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - `zbss_objtype` INT(3) NOT NULL DEFAULT '-1', - `zbss_objid` INT(32) NOT NULL, - `zbss_source` VARCHAR(20) NOT NULL, - `zbss_uid` VARCHAR(300) NOT NULL, - `zbss_origin` VARCHAR(400) NULL DEFAULT NULL, - `zbss_created` INT(14) NOT NULL, - `zbss_lastupdated` INT(14) NOT NULL, - PRIMARY KEY (`ID`), - 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); - - #} 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, - `zbs_owner` INT NOT NULL, - `zbst_contactid` INT NOT NULL, - `zbst_action` VARCHAR(50) NOT NULL, - `zbst_action_detail` LONGTEXT NOT NULL, - `zbst_referrer` VARCHAR(300) NOT NULL, - `zbst_utm_source` VARCHAR(200) NOT NULL, - `zbst_utm_medium` VARCHAR(200) NOT NULL, - `zbst_utm_name` VARCHAR(200) NOT NULL, - `zbst_utm_term` VARCHAR(200) NOT NULL, - `zbst_utm_content` VARCHAR(200) NOT NULL, - `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); - - #} 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, - `zbs_owner` INT NOT NULL, - `zbsl_objtype` INT NOT NULL, - `zbsl_objid` INT NOT NULL, - `zbsl_type` VARCHAR(200) NOT NULL, - `zbsl_shortdesc` VARCHAR(300) NULL, - `zbsl_longdesc` LONGTEXT NULL, +function zeroBSCRM_createTables() { + + global $wpdb, $ZBSCRM_t; + + // Require upgrade.php so we can use dbDelta + require_once ABSPATH . 'wp-admin/includes/upgrade.php'; + + // Where available we force InnoDB + $storageEngineLine = ''; + if ( zeroBSCRM_DB_canInnoDB() ) { + $storageEngineLine = 'ENGINE = InnoDB'; + } + + // Collation & Character Set + $collation = 'utf8_general_ci'; + $characterSet = 'utf8'; + + // We'll collect any errors as we go, exposing, if there are any, on system status page + global $zbsDB_lastError, $zbsDB_creationErrors; + + // 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'] . '( + `ID` INT NOT NULL AUTO_INCREMENT, + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + `zbsc_status` VARCHAR(100) NULL, + `zbsc_email` VARCHAR(200) NULL, + `zbsc_prefix` VARCHAR(30) NULL, + `zbsc_fname` VARCHAR(100) NULL, + `zbsc_lname` VARCHAR(100) NULL, + `zbsc_addr1` VARCHAR(200) NULL, + `zbsc_addr2` VARCHAR(200) NULL, + `zbsc_city` VARCHAR(200) NULL, + `zbsc_county` VARCHAR(200) NULL, + `zbsc_country` VARCHAR(200) NULL, + `zbsc_postcode` VARCHAR(50) NULL, + `zbsc_secaddr1` VARCHAR(200) NULL, + `zbsc_secaddr2` VARCHAR(200) NULL, + `zbsc_seccity` VARCHAR(200) NULL, + `zbsc_seccounty` VARCHAR(200) NULL, + `zbsc_seccountry` VARCHAR(200) NULL, + `zbsc_secpostcode` VARCHAR(50) NULL, + `zbsc_hometel` VARCHAR(40) NULL, + `zbsc_worktel` VARCHAR(40) NULL, + `zbsc_mobtel` VARCHAR(40) NULL, + `zbsc_wpid` INT NULL DEFAULT NULL, + `zbsc_avatar` VARCHAR(300) NULL, + `zbsc_tw` VARCHAR(100) NULL, + `zbsc_li` VARCHAR(300) NULL, + `zbsc_fb` VARCHAR(200) NULL, + `zbsc_created` INT(14) NOT NULL, + `zbsc_lastupdated` INT(14) NOT NULL, + `zbsc_lastcontacted` INT(14) NULL DEFAULT NULL, + 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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbscf_objtype` INT(4) NOT NULL, + `zbscf_objid` INT(32) NOT NULL, + `zbscf_objkey` VARCHAR(100) NOT NULL, + `zbscf_objval` VARCHAR(2000) NULL DEFAULT NULL, + `zbscf_created` INT(14) NOT NULL, + `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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbstag_objtype` INT NOT NULL, + `zbstag_name` VARCHAR(200) NOT NULL, + `zbstag_slug` VARCHAR(200) NOT NULL, + `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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbstl_objtype` INT(4) NOT NULL, + `zbstl_objid` INT NOT NULL, + `zbstl_tagid` INT NOT NULL, + PRIMARY KEY (`ID`), + 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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbsset_key` VARCHAR(100) NOT NULL DEFAULT -1, + `zbsset_val` LONGTEXT NULL DEFAULT NULL, + `zbsset_created` INT(14) NOT NULL, + `zbsset_lastupdated` INT(14) NOT NULL, + PRIMARY KEY (`ID`), + INDEX `zbsset_key` (`zbsset_key`), + INDEX (`zbs_owner`)) + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbsm_objtype` INT NOT NULL, + `zbsm_objid` INT NOT NULL, + `zbsm_key` VARCHAR(255) NOT NULL, + `zbsm_val` LONGTEXT NULL DEFAULT NULL, + `zbsm_created` INT(14) NOT NULL, + `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 ); + + #} 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, + `zbs_owner` INT NOT NULL, + `zbsseg_name` VARCHAR(120) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL, + `zbsseg_slug` VARCHAR(45) NOT NULL, + `zbsseg_matchtype` VARCHAR(10) NOT NULL, + `zbsseg_created` INT(14) NOT NULL, + `zbsseg_lastupdated` INT(14) NOT NULL, + `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 ); + + // 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, + `zbscondition_op` VARCHAR(50) NULL, + `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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbsadmlog_status` INT(3) NOT NULL, + `zbsadmlog_cat` VARCHAR(20) NULL DEFAULT NULL, + `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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbstemphash_status` INT NULL DEFAULT -1, + `zbstemphash_objtype` VARCHAR(50) NOT NULL, + `zbstemphash_objid` INT NULL DEFAULT NULL, + `zbstemphash_objhash` VARCHAR(256) NULL DEFAULT NULL, + `zbstemphash_created` INT(14) NOT NULL, + `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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbsol_objtype_from` INT(4) NOT NULL, + `zbsol_objtype_to` INT(4) NOT NULL, + `zbsol_objid_from` INT NOT NULL, + `zbsol_objid_to` INT NOT NULL, + PRIMARY KEY (`ID`), + INDEX (`zbsol_objid_from`), + INDEX (`zbsol_objid_to`)) + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + #} 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, + `aka_alias` VARCHAR(200) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL, + `aka_created` INT(14) NULL, + `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'] . "( + `ID` INT NOT NULL AUTO_INCREMENT, + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + `zbss_objtype` INT(3) NOT NULL DEFAULT '-1', + `zbss_objid` INT(32) NOT NULL, + `zbss_source` VARCHAR(20) NOT NULL, + `zbss_uid` VARCHAR(300) NOT NULL, + `zbss_origin` VARCHAR(400) NULL DEFAULT NULL, + `zbss_created` INT(14) NOT NULL, + `zbss_lastupdated` INT(14) NOT NULL, + PRIMARY KEY (`ID`), + 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 ); + + #} 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, + `zbs_owner` INT NOT NULL, + `zbst_contactid` INT NOT NULL, + `zbst_action` VARCHAR(50) NOT NULL, + `zbst_action_detail` LONGTEXT NOT NULL, + `zbst_referrer` VARCHAR(300) NOT NULL, + `zbst_utm_source` VARCHAR(200) NOT NULL, + `zbst_utm_medium` VARCHAR(200) NOT NULL, + `zbst_utm_name` VARCHAR(200) NOT NULL, + `zbst_utm_term` VARCHAR(200) NOT NULL, + `zbst_utm_content` VARCHAR(200) NOT NULL, + `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 ); + + #} 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, + `zbs_owner` INT NOT NULL, + `zbsl_objtype` INT NOT NULL, + `zbsl_objid` INT NOT NULL, + `zbsl_type` VARCHAR(200) NOT NULL, + `zbsl_shortdesc` VARCHAR(300) NULL, + `zbsl_longdesc` LONGTEXT NULL, `zbsl_pinned` INT(1) NULL, - `zbsl_created` INT(14) NOT NULL, - `zbsl_lastupdated` INT(14) NOT NULL, - PRIMARY KEY (`ID`), - INDEX (`zbsl_objid`), - INDEX `zbsl_created` (`zbsl_created`) USING BTREE) - ".$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'] ."( - `ID` INT NOT NULL AUTO_INCREMENT, - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - `zbsmail_active` INT NOT NULL, - `zbsmail_id` INT NOT NULL, - `zbsmail_deliverymethod` VARCHAR(200) NOT NULL, - `zbsmail_fromname` VARCHAR(200) NULL, - `zbsmail_fromaddress` VARCHAR(200) NULL, - `zbsmail_replyto` VARCHAR(200) NULL, - `zbsmail_ccto` VARCHAR(200) NULL, - `zbsmail_bccto` VARCHAR(200) NULL, - `zbsmail_subject` VARCHAR(200) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NULL DEFAULT NULL, - `zbsmail_body` LONGTEXT NULL DEFAULT NULL, - `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); - - // 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, - `zbs_owner` int(11) NOT NULL, - `zbsmail_type` int(11) NOT NULL, - `zbsmail_sender_thread` int(11) NOT NULL, - `zbsmail_sender_email` varchar(200) NOT NULL, - `zbsmail_sender_wpid` int(11) NOT NULL, - `zbsmail_sender_mailbox_id` int(11) NOT NULL, - `zbsmail_sender_mailbox_name` varchar(200) DEFAULT NULL, - `zbsmail_receiver_email` varchar(200) NOT NULL, - `zbsmail_sent` int(11) NOT NULL, - `zbsmail_target_objid` int(11) NOT NULL, - `zbsmail_assoc_objid` int(11) NOT NULL, - `zbsmail_subject` varchar(200) DEFAULT NULL, - `zbsmail_content` longtext, - `zbsmail_hash` varchar(128) DEFAULT NULL, - `zbsmail_status` varchar(120) DEFAULT NULL, - `zbsmail_sender_maildelivery_key` varchar(200) DEFAULT NULL, - `zbsmail_starred` int(11) DEFAULT NULL, - `zbsmail_opened` int(11) NOT NULL, - `zbsmail_clicked` int(11) NOT NULL, - `zbsmail_firstopened` int(14) NOT NULL, - `zbsmail_lastopened` int(14) NOT NULL, - `zbsmail_lastclicked` int(14) NOT NULL, - `zbsmail_created` int(14) NOT NULL, - PRIMARY KEY (`ID`), - INDEX (`zbsmail_sender_wpid`), - INDEX (`zbsmail_sender_mailbox_id`)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - // 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, - `zbs_owner` int(11) NOT NULL, - `job` VARCHAR(100) NOT NULL, - `jobstatus` INT(3) NULL, - `jobstarted` INT(14) NOT NULL, - `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'] ."( - `ID` INT NOT NULL AUTO_INCREMENT, - `zbs_site` int(11) DEFAULT NULL, - `zbs_team` int(11) DEFAULT NULL, - `zbs_owner` int(11) NOT NULL, - `zbsc_tax_name` VARCHAR(100) NULL, - `zbsc_rate` DECIMAL(20,10) NOT NULL DEFAULT 0.0000000000, - `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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsco_status` VARCHAR(50) NULL DEFAULT NULL, - `zbsco_name` VARCHAR(100) NULL DEFAULT NULL, - `zbsco_email` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_addr1` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_addr2` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_city` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_county` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_country` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_postcode` VARCHAR(50) NULL DEFAULT NULL, - `zbsco_secaddr1` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_secaddr2` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_seccity` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_seccounty` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_seccountry` VARCHAR(200) NULL DEFAULT NULL, - `zbsco_secpostcode` VARCHAR(50) NULL DEFAULT NULL, - `zbsco_maintel` VARCHAR(40) NULL DEFAULT NULL, - `zbsco_sectel` VARCHAR(40) NULL DEFAULT NULL, - `zbsco_wpid` INT NULL DEFAULT NULL, - `zbsco_avatar` VARCHAR(300) NULL DEFAULT NULL, - `zbsco_tw` VARCHAR(100) NULL, - `zbsco_li` VARCHAR(300) NULL, - `zbsco_fb` VARCHAR(200) NULL, - `zbsco_created` INT(14) NOT NULL, - `zbsco_lastupdated` INT(14) NOT NULL, - `zbsco_lastcontacted` INT(14) NULL DEFAULT NULL, - PRIMARY KEY (`ID`), - INDEX `wpid` (`zbsco_wpid` ASC), - 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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbse_title` VARCHAR(255) NULL DEFAULT NULL, - `zbse_desc` LONGTEXT NULL DEFAULT NULL, - `zbse_start` INT(14) NOT NULL, - `zbse_end` INT(14) NOT NULL, - `zbse_complete` TINYINT(1) NOT NULL DEFAULT -1, - `zbse_show_on_portal` TINYINT(1) NOT NULL DEFAULT -1, - `zbse_show_on_cal` TINYINT(1) NOT NULL DEFAULT -1, - `zbse_created` INT(14) NOT NULL, - `zbse_lastupdated` INT(14) NULL DEFAULT NULL, - PRIMARY KEY (`ID`), - INDEX `title` (`zbse_title` ASC), - 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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbser_event` INT NOT NULL, - `zbser_remind_at` INT NOT NULL DEFAULT -1, - `zbser_sent` TINYINT NOT NULL DEFAULT -1, - `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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsf_title` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_style` VARCHAR(20) NOT NULL, - `zbsf_views` INT(10) NULL DEFAULT 0, - `zbsf_conversions` INT(10) NULL DEFAULT 0, - `zbsf_label_header` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_label_subheader` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_label_firstname` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_label_lastname` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_label_email` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_label_message` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_label_button` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_label_successmsg` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_label_spammsg` VARCHAR(200) NULL DEFAULT NULL, - `zbsf_include_terms_check` TINYINT(1) NOT NULL DEFAULT -1, - `zbsf_terms_url` VARCHAR(300) NULL DEFAULT NULL, - `zbsf_redir_url` VARCHAR(300) NULL DEFAULT NULL, - `zbsf_font` VARCHAR(100) NULL DEFAULT NULL, - `zbsf_colour_bg` VARCHAR(100) NULL DEFAULT NULL, - `zbsf_colour_font` VARCHAR(100) NULL DEFAULT NULL, - `zbsf_colour_emphasis` VARCHAR(100) NULL DEFAULT NULL, - `zbsf_created` INT(14) NOT NULL, - `zbsf_lastupdated` INT(14) NOT NULL, - PRIMARY KEY (`ID`), - INDEX `title` (`zbsf_title` ASC), - INDEX `created` (`zbsf_created` ASC)) - ".$storageEngineLine." - DEFAULT CHARACTER SET = ".$characterSet." - COLLATE = ".$collation.";"; - zeroBSCRM_db_runDelta($sql); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsi_id_override` VARCHAR(128) NULL DEFAULT NULL, - `zbsi_parent` INT NULL DEFAULT NULL, - `zbsi_status` VARCHAR(50) NOT NULL, - `zbsi_hash` VARCHAR(64) NULL DEFAULT NULL, - `zbsi_send_attachments` TINYINT(1) NOT NULL DEFAULT -1, - `zbsi_pdf_template` VARCHAR(128) NULL DEFAULT NULL, - `zbsi_portal_template` VARCHAR(128) NULL DEFAULT NULL, - `zbsi_email_template` VARCHAR(128) NULL DEFAULT NULL, - `zbsi_invoice_frequency` INT(4) NULL DEFAULT -1, - `zbsi_currency` VARCHAR(4) NOT NULL DEFAULT -1, - `zbsi_pay_via` INT(4) NULL DEFAULT NULL, - `zbsi_logo_url` VARCHAR(300) NULL DEFAULT NULL, - `zbsi_address_to_objtype` INT(2) NOT NULL DEFAULT -1, - `zbsi_addressed_from` VARCHAR(600) NULL DEFAULT NULL, - `zbsi_addressed_to` VARCHAR(600) NULL DEFAULT NULL, - `zbsi_allow_partial` TINYINT(1) NOT NULL DEFAULT -1, - `zbsi_allow_tip` TINYINT(1) NOT NULL DEFAULT -1, - `zbsi_hours_or_quantity` TINYINT(1) NOT NULL DEFAULT 1, - `zbsi_date` INT(14) NOT NULL, - `zbsi_due_date` INT(14) NULL DEFAULT NULL, - `zbsi_paid_date` INT(14) NULL DEFAULT -1, - `zbsi_hash_viewed` INT(14) NULL DEFAULT -1, - `zbsi_hash_viewed_count` INT(10) NULL DEFAULT 0, - `zbsi_portal_viewed` INT(14) NULL DEFAULT -1, - `zbsi_portal_viewed_count` INT(10) NULL DEFAULT 0, - `zbsi_net` DECIMAL(18,2) NOT NULL DEFAULT 0.00, - `zbsi_discount` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsi_discount_type` VARCHAR(20) NULL DEFAULT NULL, - `zbsi_shipping` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsi_shipping_taxes` VARCHAR(40) NULL DEFAULT NULL, - `zbsi_shipping_tax` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsi_taxes` VARCHAR(40) NULL DEFAULT NULL, - `zbsi_tax` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsi_total` DECIMAL(18,2) NOT NULL DEFAULT 0.00, - `zbsi_created` INT(14) NOT NULL, - `zbsi_lastupdated` INT(14) NOT NULL, - PRIMARY KEY (`ID`), - INDEX `idoverride` (`zbsi_id_override` ASC), - INDEX `parent` (`zbsi_parent` ASC), - 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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbsli_order` INT NULL DEFAULT NULL, - `zbsli_title` VARCHAR(300) NULL DEFAULT NULL, - `zbsli_desc` VARCHAR(300) NULL DEFAULT NULL, - `zbsli_quantity` decimal(18,2) NULL DEFAULT NULL, - `zbsli_price` DECIMAL(18,2) NOT NULL DEFAULT 0.00, - `zbsli_currency` VARCHAR(4) NOT NULL DEFAULT -1, - `zbsli_net` DECIMAL(18,2) NOT NULL DEFAULT 0.00, - `zbsli_discount` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsli_fee` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsli_shipping` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsli_shipping_taxes` VARCHAR(40) NULL DEFAULT NULL, - `zbsli_shipping_tax` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsli_taxes` VARCHAR(40) NULL DEFAULT NULL, - `zbsli_tax` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsli_total` DECIMAL(18,2) NOT NULL DEFAULT 0.00, - `zbsli_created` INT(14) NOT NULL, - `zbsli_lastupdated` INT(14) NOT NULL, - 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'] ."( - `ID` INT NOT NULL AUTO_INCREMENT, - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - `zbsq_id_override` VARCHAR(128) NULL DEFAULT NULL, - `zbsq_title` VARCHAR(255) NULL DEFAULT NULL, - `zbsq_currency` VARCHAR(4) NOT NULL DEFAULT -1, - `zbsq_value` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsq_date` INT(14) NOT NULL, - `zbsq_template` VARCHAR(200) NULL DEFAULT NULL, - `zbsq_content` LONGTEXT NULL DEFAULT NULL, - `zbsq_notes` LONGTEXT NULL DEFAULT NULL, - `zbsq_hash` VARCHAR(64) NULL DEFAULT NULL, - `zbsq_send_attachments` TINYINT(1) NOT NULL DEFAULT -1, - `zbsq_lastviewed` INT(14) NULL DEFAULT -1, - `zbsq_viewed_count` INT(10) NULL DEFAULT 0, - `zbsq_accepted` INT(14) NULL DEFAULT -1, - `zbsq_acceptedsigned` VARCHAR(200) NULL DEFAULT NULL, - `zbsq_acceptedip` VARCHAR(64) NULL DEFAULT NULL, - `zbsq_created` INT(14) NOT NULL, - `zbsq_lastupdated` INT(14) NOT NULL, - PRIMARY KEY (`ID`), - INDEX `title` (`zbsq_title` ASC), - INDEX `dateint` (`zbsq_date` ASC), - 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'] ."( - `ID` INT NOT NULL AUTO_INCREMENT, - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - `zbsqt_title` VARCHAR(255) NULL DEFAULT NULL, - `zbsqt_value` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbsqt_date_str` VARCHAR(20) NULL DEFAULT NULL, - `zbsqt_date` INT(14) NULL DEFAULT NULL, - `zbsqt_content` LONGTEXT NULL DEFAULT NULL, - `zbsqt_notes` LONGTEXT NULL DEFAULT NULL, - `zbsqt_currency` VARCHAR(4) NOT NULL DEFAULT -1, - `zbsqt_created` INT(14) NOT NULL, - `zbsqt_lastupdated` INT(14) NOT NULL, - 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'] ."( - `ID` INT NOT NULL AUTO_INCREMENT, - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - `zbst_status` VARCHAR(50) NOT NULL, - `zbst_type` VARCHAR(50) DEFAULT NULL, - `zbst_ref` VARCHAR(120) NOT NULL, - `zbst_origin` VARCHAR(100) NULL DEFAULT NULL, - `zbst_parent` INT NULL DEFAULT NULL, - `zbst_hash` VARCHAR(64) NULL DEFAULT NULL, - `zbst_title` VARCHAR(200) NULL DEFAULT NULL, - `zbst_desc` VARCHAR(200) NULL DEFAULT NULL, - `zbst_date` INT(14) NULL DEFAULT NULL, - `zbst_customer_ip` VARCHAR(45) NULL DEFAULT NULL, - `zbst_currency` VARCHAR(4) NOT NULL DEFAULT -1, - `zbst_net` DECIMAL(18,2) NOT NULL DEFAULT 0.00, - `zbst_fee` DECIMAL(18,2) NOT NULL DEFAULT 0.00, - `zbst_discount` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbst_shipping` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbst_shipping_taxes` VARCHAR(40) NULL DEFAULT NULL, - `zbst_shipping_tax` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbst_taxes` VARCHAR(40) NULL DEFAULT NULL, - `zbst_tax` DECIMAL(18,2) NULL DEFAULT 0.00, - `zbst_total` DECIMAL(18,2) NOT NULL DEFAULT 0.00, - `zbst_date_paid` INT(14) NULL DEFAULT NULL, - `zbst_date_completed` INT(14) NULL DEFAULT NULL, - `zbst_created` INT(14) NOT NULL, - `zbst_lastupdated` INT(14) NOT NULL, - PRIMARY KEY (`ID`), - INDEX `status` (`zbst_status` ASC), - INDEX `ref` (`zbst_ref` ASC), - INDEX `transtype` (`zbst_type` ASC), - INDEX `transorigin` (`zbst_origin` ASC), - INDEX `parent` (`zbst_parent` ASC), - INDEX `hash` (`zbst_hash` ASC), - 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); - - // 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, - `zbs_owner` INT NOT NULL, - `zbssl_reqtype` VARCHAR(20) NOT NULL, - `zbssl_ip` VARCHAR(200) NULL DEFAULT NULL, - `zbssl_reqhash` VARCHAR(128) NULL DEFAULT NULL, - `zbssl_reqid` INT(11) NULL DEFAULT NULL, - `zbssl_loggedin_id` INT(11) NULL DEFAULT NULL, - `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); + `zbsl_created` INT(14) NOT NULL, + `zbsl_lastupdated` INT(14) NOT NULL, + PRIMARY KEY (`ID`), + INDEX (`zbsl_objid`), + INDEX `zbsl_created` (`zbsl_created`) USING BTREE) + ' . $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'] . "( + `ID` INT NOT NULL AUTO_INCREMENT, + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + `zbsmail_active` INT NOT NULL, + `zbsmail_id` INT NOT NULL, + `zbsmail_deliverymethod` VARCHAR(200) NOT NULL, + `zbsmail_fromname` VARCHAR(200) NULL, + `zbsmail_fromaddress` VARCHAR(200) NULL, + `zbsmail_replyto` VARCHAR(200) NULL, + `zbsmail_ccto` VARCHAR(200) NULL, + `zbsmail_bccto` VARCHAR(200) NULL, + `zbsmail_subject` VARCHAR(200) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NULL DEFAULT NULL, + `zbsmail_body` LONGTEXT NULL DEFAULT NULL, + `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 ); + + // 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, + `zbs_owner` int(11) NOT NULL, + `zbsmail_type` int(11) NOT NULL, + `zbsmail_sender_thread` int(11) NOT NULL, + `zbsmail_sender_email` varchar(200) NOT NULL, + `zbsmail_sender_wpid` int(11) NOT NULL, + `zbsmail_sender_mailbox_id` int(11) NOT NULL, + `zbsmail_sender_mailbox_name` varchar(200) DEFAULT NULL, + `zbsmail_receiver_email` varchar(200) NOT NULL, + `zbsmail_sent` int(11) NOT NULL, + `zbsmail_target_objid` int(11) NOT NULL, + `zbsmail_assoc_objid` int(11) NOT NULL, + `zbsmail_subject` varchar(200) DEFAULT NULL, + `zbsmail_content` longtext, + `zbsmail_hash` varchar(128) DEFAULT NULL, + `zbsmail_status` varchar(120) DEFAULT NULL, + `zbsmail_sender_maildelivery_key` varchar(200) DEFAULT NULL, + `zbsmail_starred` int(11) DEFAULT NULL, + `zbsmail_opened` int(11) NOT NULL, + `zbsmail_clicked` int(11) NOT NULL, + `zbsmail_firstopened` int(14) NOT NULL, + `zbsmail_lastopened` int(14) NOT NULL, + `zbsmail_lastclicked` int(14) NOT NULL, + `zbsmail_created` int(14) NOT NULL, + PRIMARY KEY (`ID`), + INDEX (`zbsmail_sender_wpid`), + INDEX (`zbsmail_sender_mailbox_id`)) + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + // 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, + `zbs_owner` int(11) NOT NULL, + `job` VARCHAR(100) NOT NULL, + `jobstatus` INT(3) NULL, + `jobstarted` INT(14) NOT NULL, + `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'] . '( + `ID` INT NOT NULL AUTO_INCREMENT, + `zbs_site` int(11) DEFAULT NULL, + `zbs_team` int(11) DEFAULT NULL, + `zbs_owner` int(11) NOT NULL, + `zbsc_tax_name` VARCHAR(100) NULL, + `zbsc_rate` DECIMAL(20,10) NOT NULL DEFAULT 0.0000000000, + `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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbsco_status` VARCHAR(50) NULL DEFAULT NULL, + `zbsco_name` VARCHAR(100) NULL DEFAULT NULL, + `zbsco_email` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_addr1` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_addr2` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_city` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_county` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_country` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_postcode` VARCHAR(50) NULL DEFAULT NULL, + `zbsco_secaddr1` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_secaddr2` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_seccity` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_seccounty` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_seccountry` VARCHAR(200) NULL DEFAULT NULL, + `zbsco_secpostcode` VARCHAR(50) NULL DEFAULT NULL, + `zbsco_maintel` VARCHAR(40) NULL DEFAULT NULL, + `zbsco_sectel` VARCHAR(40) NULL DEFAULT NULL, + `zbsco_wpid` INT NULL DEFAULT NULL, + `zbsco_avatar` VARCHAR(300) NULL DEFAULT NULL, + `zbsco_tw` VARCHAR(100) NULL, + `zbsco_li` VARCHAR(300) NULL, + `zbsco_fb` VARCHAR(200) NULL, + `zbsco_created` INT(14) NOT NULL, + `zbsco_lastupdated` INT(14) NOT NULL, + `zbsco_lastcontacted` INT(14) NULL DEFAULT NULL, + PRIMARY KEY (`ID`), + INDEX `wpid` (`zbsco_wpid` ASC), + 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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbse_title` VARCHAR(255) NULL DEFAULT NULL, + `zbse_desc` LONGTEXT NULL DEFAULT NULL, + `zbse_start` INT(14) NOT NULL, + `zbse_end` INT(14) NOT NULL, + `zbse_complete` TINYINT(1) NOT NULL DEFAULT -1, + `zbse_show_on_portal` TINYINT(1) NOT NULL DEFAULT -1, + `zbse_show_on_cal` TINYINT(1) NOT NULL DEFAULT -1, + `zbse_created` INT(14) NOT NULL, + `zbse_lastupdated` INT(14) NULL DEFAULT NULL, + PRIMARY KEY (`ID`), + INDEX `title` (`zbse_title` ASC), + 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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbser_event` INT NOT NULL, + `zbser_remind_at` INT NOT NULL DEFAULT -1, + `zbser_sent` TINYINT NOT NULL DEFAULT -1, + `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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbsf_title` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_style` VARCHAR(20) NOT NULL, + `zbsf_views` INT(10) NULL DEFAULT 0, + `zbsf_conversions` INT(10) NULL DEFAULT 0, + `zbsf_label_header` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_label_subheader` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_label_firstname` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_label_lastname` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_label_email` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_label_message` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_label_button` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_label_successmsg` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_label_spammsg` VARCHAR(200) NULL DEFAULT NULL, + `zbsf_include_terms_check` TINYINT(1) NOT NULL DEFAULT -1, + `zbsf_terms_url` VARCHAR(300) NULL DEFAULT NULL, + `zbsf_redir_url` VARCHAR(300) NULL DEFAULT NULL, + `zbsf_font` VARCHAR(100) NULL DEFAULT NULL, + `zbsf_colour_bg` VARCHAR(100) NULL DEFAULT NULL, + `zbsf_colour_font` VARCHAR(100) NULL DEFAULT NULL, + `zbsf_colour_emphasis` VARCHAR(100) NULL DEFAULT NULL, + `zbsf_created` INT(14) NOT NULL, + `zbsf_lastupdated` INT(14) NOT NULL, + PRIMARY KEY (`ID`), + INDEX `title` (`zbsf_title` ASC), + INDEX `created` (`zbsf_created` ASC)) + ' . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . ' + COLLATE = ' . $collation . ';'; + zeroBSCRM_db_runDelta( $sql ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbsi_id_override` VARCHAR(128) NULL DEFAULT NULL, + `zbsi_parent` INT NULL DEFAULT NULL, + `zbsi_status` VARCHAR(50) NOT NULL, + `zbsi_hash` VARCHAR(64) NULL DEFAULT NULL, + `zbsi_send_attachments` TINYINT(1) NOT NULL DEFAULT -1, + `zbsi_pdf_template` VARCHAR(128) NULL DEFAULT NULL, + `zbsi_portal_template` VARCHAR(128) NULL DEFAULT NULL, + `zbsi_email_template` VARCHAR(128) NULL DEFAULT NULL, + `zbsi_invoice_frequency` INT(4) NULL DEFAULT -1, + `zbsi_currency` VARCHAR(4) NOT NULL DEFAULT -1, + `zbsi_pay_via` INT(4) NULL DEFAULT NULL, + `zbsi_logo_url` VARCHAR(300) NULL DEFAULT NULL, + `zbsi_address_to_objtype` INT(2) NOT NULL DEFAULT -1, + `zbsi_addressed_from` VARCHAR(600) NULL DEFAULT NULL, + `zbsi_addressed_to` VARCHAR(600) NULL DEFAULT NULL, + `zbsi_allow_partial` TINYINT(1) NOT NULL DEFAULT -1, + `zbsi_allow_tip` TINYINT(1) NOT NULL DEFAULT -1, + `zbsi_hours_or_quantity` TINYINT(1) NOT NULL DEFAULT 1, + `zbsi_date` INT(14) NOT NULL, + `zbsi_due_date` INT(14) NULL DEFAULT NULL, + `zbsi_paid_date` INT(14) NULL DEFAULT -1, + `zbsi_hash_viewed` INT(14) NULL DEFAULT -1, + `zbsi_hash_viewed_count` INT(10) NULL DEFAULT 0, + `zbsi_portal_viewed` INT(14) NULL DEFAULT -1, + `zbsi_portal_viewed_count` INT(10) NULL DEFAULT 0, + `zbsi_net` DECIMAL(18,2) NOT NULL DEFAULT 0.00, + `zbsi_discount` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsi_discount_type` VARCHAR(20) NULL DEFAULT NULL, + `zbsi_shipping` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsi_shipping_taxes` VARCHAR(40) NULL DEFAULT NULL, + `zbsi_shipping_tax` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsi_taxes` VARCHAR(40) NULL DEFAULT NULL, + `zbsi_tax` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsi_total` DECIMAL(18,2) NOT NULL DEFAULT 0.00, + `zbsi_created` INT(14) NOT NULL, + `zbsi_lastupdated` INT(14) NOT NULL, + PRIMARY KEY (`ID`), + INDEX `idoverride` (`zbsi_id_override` ASC), + INDEX `parent` (`zbsi_parent` ASC), + 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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbsli_order` INT NULL DEFAULT NULL, + `zbsli_title` VARCHAR(300) NULL DEFAULT NULL, + `zbsli_desc` VARCHAR(300) NULL DEFAULT NULL, + `zbsli_quantity` decimal(18,2) NULL DEFAULT NULL, + `zbsli_price` DECIMAL(18,2) NOT NULL DEFAULT 0.00, + `zbsli_currency` VARCHAR(4) NOT NULL DEFAULT -1, + `zbsli_net` DECIMAL(18,2) NOT NULL DEFAULT 0.00, + `zbsli_discount` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsli_fee` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsli_shipping` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsli_shipping_taxes` VARCHAR(40) NULL DEFAULT NULL, + `zbsli_shipping_tax` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsli_taxes` VARCHAR(40) NULL DEFAULT NULL, + `zbsli_tax` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsli_total` DECIMAL(18,2) NOT NULL DEFAULT 0.00, + `zbsli_created` INT(14) NOT NULL, + `zbsli_lastupdated` INT(14) NOT NULL, + 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'] . '( + `ID` INT NOT NULL AUTO_INCREMENT, + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + `zbsq_id_override` VARCHAR(128) NULL DEFAULT NULL, + `zbsq_title` VARCHAR(255) NULL DEFAULT NULL, + `zbsq_currency` VARCHAR(4) NOT NULL DEFAULT -1, + `zbsq_value` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsq_date` INT(14) NOT NULL, + `zbsq_template` VARCHAR(200) NULL DEFAULT NULL, + `zbsq_content` LONGTEXT NULL DEFAULT NULL, + `zbsq_notes` LONGTEXT NULL DEFAULT NULL, + `zbsq_hash` VARCHAR(64) NULL DEFAULT NULL, + `zbsq_send_attachments` TINYINT(1) NOT NULL DEFAULT -1, + `zbsq_lastviewed` INT(14) NULL DEFAULT -1, + `zbsq_viewed_count` INT(10) NULL DEFAULT 0, + `zbsq_accepted` INT(14) NULL DEFAULT -1, + `zbsq_acceptedsigned` VARCHAR(200) NULL DEFAULT NULL, + `zbsq_acceptedip` VARCHAR(64) NULL DEFAULT NULL, + `zbsq_created` INT(14) NOT NULL, + `zbsq_lastupdated` INT(14) NOT NULL, + PRIMARY KEY (`ID`), + INDEX `title` (`zbsq_title` ASC), + INDEX `dateint` (`zbsq_date` ASC), + 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'] . '( + `ID` INT NOT NULL AUTO_INCREMENT, + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + `zbsqt_title` VARCHAR(255) NULL DEFAULT NULL, + `zbsqt_value` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbsqt_date_str` VARCHAR(20) NULL DEFAULT NULL, + `zbsqt_date` INT(14) NULL DEFAULT NULL, + `zbsqt_content` LONGTEXT NULL DEFAULT NULL, + `zbsqt_notes` LONGTEXT NULL DEFAULT NULL, + `zbsqt_currency` VARCHAR(4) NOT NULL DEFAULT -1, + `zbsqt_created` INT(14) NOT NULL, + `zbsqt_lastupdated` INT(14) NOT NULL, + 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'] . '( + `ID` INT NOT NULL AUTO_INCREMENT, + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + `zbst_status` VARCHAR(50) NOT NULL, + `zbst_type` VARCHAR(50) DEFAULT NULL, + `zbst_ref` VARCHAR(120) NOT NULL, + `zbst_origin` VARCHAR(100) NULL DEFAULT NULL, + `zbst_parent` INT NULL DEFAULT NULL, + `zbst_hash` VARCHAR(64) NULL DEFAULT NULL, + `zbst_title` VARCHAR(200) NULL DEFAULT NULL, + `zbst_desc` VARCHAR(200) NULL DEFAULT NULL, + `zbst_date` INT(14) NULL DEFAULT NULL, + `zbst_customer_ip` VARCHAR(45) NULL DEFAULT NULL, + `zbst_currency` VARCHAR(4) NOT NULL DEFAULT -1, + `zbst_net` DECIMAL(18,2) NOT NULL DEFAULT 0.00, + `zbst_fee` DECIMAL(18,2) NOT NULL DEFAULT 0.00, + `zbst_discount` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbst_shipping` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbst_shipping_taxes` VARCHAR(40) NULL DEFAULT NULL, + `zbst_shipping_tax` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbst_taxes` VARCHAR(40) NULL DEFAULT NULL, + `zbst_tax` DECIMAL(18,2) NULL DEFAULT 0.00, + `zbst_total` DECIMAL(18,2) NOT NULL DEFAULT 0.00, + `zbst_date_paid` INT(14) NULL DEFAULT NULL, + `zbst_date_completed` INT(14) NULL DEFAULT NULL, + `zbst_created` INT(14) NOT NULL, + `zbst_lastupdated` INT(14) NOT NULL, + PRIMARY KEY (`ID`), + INDEX `status` (`zbst_status` ASC), + INDEX `ref` (`zbst_ref` ASC), + INDEX `transtype` (`zbst_type` ASC), + INDEX `transorigin` (`zbst_origin` ASC), + INDEX `parent` (`zbst_parent` ASC), + INDEX `hash` (`zbst_hash` ASC), + 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 ); + + // 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, + `zbs_owner` INT NOT NULL, + `zbssl_reqtype` VARCHAR(20) NOT NULL, + `zbssl_ip` VARCHAR(200) NULL DEFAULT NULL, + `zbssl_reqhash` VARCHAR(128) NULL DEFAULT NULL, + `zbssl_reqid` INT(11) NULL DEFAULT NULL, + `zbssl_loggedin_id` INT(11) NULL DEFAULT NULL, + `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 ); // Add table to store automation workflows. // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase @@ -876,17 +879,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 +914,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 +950,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; } /** @@ -1041,23 +1042,23 @@ function jpcrm_create_notifications_table() { // Table creation SQL // phpcs:disable $sql = 'CREATE TABLE IF NOT EXISTS ' . $ZBSCRM_t['notifications'] . "( - `id` INT(32) UNSIGNED NOT NULL AUTO_INCREMENT, - `zbs_site` INT NULL DEFAULT NULL, - `zbs_team` INT NULL DEFAULT NULL, - `zbs_owner` INT NOT NULL, - `zbsnotify_recipient_id` INT(32) NOT NULL, - `zbsnotify_sender_id` INT(32) NOT NULL, - `zbsnotify_unread` TINYINT(1) NOT NULL DEFAULT '1', - `zbsnotify_emailed` TINYINT(1) NOT NULL DEFAULT '0', - `zbsnotify_type` VARCHAR(255) NOT NULL DEFAULT '', - `zbsnotify_parameters` TEXT NOT NULL, - `zbsnotify_reference_id` INT(32) NOT NULL, - `zbsnotify_created_at` INT(18) NOT NULL, - PRIMARY KEY (`id`)) - " . $storageEngineLine . ' - DEFAULT CHARACTER SET = ' . $characterSet . " - COLLATE = " . $collation . ";"; - // phpcs:enable + `id` INT(32) UNSIGNED NOT NULL AUTO_INCREMENT, + `zbs_site` INT NULL DEFAULT NULL, + `zbs_team` INT NULL DEFAULT NULL, + `zbs_owner` INT NOT NULL, + `zbsnotify_recipient_id` INT(32) NOT NULL, + `zbsnotify_sender_id` INT(32) NOT NULL, + `zbsnotify_unread` TINYINT(1) NOT NULL DEFAULT '1', + `zbsnotify_emailed` TINYINT(1) NOT NULL DEFAULT '0', + `zbsnotify_type` VARCHAR(255) NOT NULL DEFAULT '', + `zbsnotify_parameters` TEXT NOT NULL, + `zbsnotify_reference_id` INT(32) NOT NULL, + `zbsnotify_created_at` INT(18) NOT NULL, + PRIMARY KEY (`id`)) + " . $storageEngineLine . ' + DEFAULT CHARACTER SET = ' . $characterSet . " + COLLATE = " . $collation . ";"; + // phpcs:enable // Run the query zeroBSCRM_db_runDelta( $sql ); @@ -1072,15 +1073,15 @@ function jpcrm_create_notifications_table() { return $table_exists; } -/* ====================================================== - / Table Creation - ====================================================== */ - - +/* +====================================================== + / Table Creation + ====================================================== */ -/* ====================================================== - Uninstall Funcs - ====================================================== */ +/* +====================================================== + Uninstall Funcs + ====================================================== */ /** * dangerous, brutal, savage. @@ -1097,29 +1098,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 +1142,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 - + // phpcs:enable 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(); + #} 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 ) ) ); + } -/* ====================================================== - / Uninstall Funcs - ====================================================== */ + #} 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..5f4ca693bd21 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Delete.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Delete.php @@ -1,5 +1,5 @@ - 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..cd6046b85bfc 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Edit.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Edit.php @@ -1,5 +1,5 @@ - 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 +220,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..c9e1f019cfc9 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.ErrorCodes.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.ErrorCodes.php @@ -1,5 +1,5 @@ - 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..214434173c25 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.ExternalSources.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.ExternalSources.php @@ -1,5 +1,5 @@ - '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 ); return $external_sources; - // 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 +186,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 +214,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..ecaa1bd1fae6 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.FileUploads.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.FileUploads.php @@ -1,5 +1,5 @@ - 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 +416,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 +461,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 +477,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 +507,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 +529,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 +544,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 +559,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 +574,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 +589,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 +620,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 +641,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 +650,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 +661,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..11e90fdb08c0 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.FormatHelpers.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.FormatHelpers.php @@ -1,5 +1,5 @@ - 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 ($contactID > 0 && $tags == false) $tags = zeroBSCRM_getCustomerTagsByID($contactID); - - if (count($tags) > 0) - foreach ($tags as $tag){ + 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; - } - - $short_tag_name = $trim && strlen($tagName) > 50 ? substr($tagName,0,10)."..." : $tagName; + // 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 ) . ''; - $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 +185,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 +285,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 +337,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 +359,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 +374,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 +386,7 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa ?>
  • >
    @@ -399,12 +399,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 +413,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 +433,7 @@ function zeroBSCRM_html_contactTimeline($contactID=-1,$logs=false,$contactObj=fa
@@ -441,132 +441,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 +701,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 +994,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 +1002,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 +1023,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 +1047,12 @@ function zeroBSCRM_getObjNav( $id = -1, $key = '', $type = ZBS_TYPE_CONTACT ) { } return $html; - } -/* ====================================================== - / Object Nav - ====================================================== */ +/* +====================================================== + / Object Nav + ====================================================== */ /** * Return table options button @@ -1030,18 +1061,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 +1100,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 +1238,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': ?>
@@ -1295,39 +1329,39 @@ function zeroBSCRM_html_editField($dataArr=array(), $fieldKey = false, $fieldVal name="" id="" class="form-control widetext zbs-dc" - placeholder="" - value="" + placeholder="" + value="" autocomplete="" /> -
+
- +
@@ -1337,16 +1371,16 @@ class="form-control numbersOnly zbs-dc" id="" class="form-control numbersOnly zbs-dc" - placeholder="" - value="" + placeholder="" + value="" autocomplete="" />
-
@@ -1356,395 +1390,397 @@ class="form-control numbersOnly zbs-dc" id="" class="form-control intOnly zbs-dc" - placeholder="" - value="" + placeholder="" + value="" autocomplete="" />
-
- +
- settings->get('showprefix') == 0 && $fieldKey == 'prefix') { - break; - } + case 'select': + //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'); ?>
- - ' . esc_html( $value ) . ''; ?> + + ' . esc_html( $value ) . ''; ?> - '. esc_html__('SMS','zero-bs-crm').': ' . esc_html( $customerMob ) . ''; + $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 ) . ''; - } + } - ?> + ?>
- - // 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 ?>
-
+
- + -
- +
- +
-
- + ?> +
-
- '; + // 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] != ''){ - - $optIndex = 0; - - foreach ($options as $opt){ - - echo '
'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - $optIndex++; - - } - - } else { - echo ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } +
+ +
+ -
- -
- 0){ + if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ + + $optIndex = 0; - break; + foreach ($options as $opt){ + + echo '
'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + + $optIndex++; + + } + + } else { + echo ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - // tax - case 'tax': + ?> +
+ +
+
- - + ?> + +
- '.$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': - ?> - -
+ ?> + +
- + -
- + - + ?> + - + - - + ?> + - + - - + ?> + - + - + } + ?> - - + ?> + - + - settings->get('showprefix') == 0 && $fieldKey == 'prefix') { - break; + break; } - ?> - - + 0){ + if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){ + + // if $default, use that + $selectVal = ''; + if ($value !== -99 && !empty($value)){ + $selectVal = $value; + } elseif (!empty($default)) + $selectVal = $default; + + //catcher + echo ''; + + foreach ($options as $opt){ + + echo ''; - } + } - } else echo ''; + } else echo ''; - ?> - - - + + + settings->get('clicktocall'); + // Click 2 call? + $click2call = $zbs->settings->get('clicktocall'); - ?> - + ?> + - - ' . esc_html( $value ) . ''; ?> + + ' . esc_html( $value ) . ''; ?> - '. esc_html__('SMS','zero-bs-crm').': ' . esc_html( $customerMob ) . ''; + $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 ) . ''; - } + } - ?> - + - // 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 - ?> - -
+ ?> + +
- + -
- + - - - + + + - - + 0){ - if (isset($countries) && count($countries) > 0){ + #if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){ + if (isset($countries) && count($countries) > 0){ - //catcher - echo ''; + //catcher + echo ''; - foreach ($countries as $countryKey => $country){ + foreach ($countries as $countryKey => $country){ - // temporary fix for people storing "United States" but also "US" - // needs a migration to iso country code, for now, catch the latter (only 1 user via api) + // temporary fix for people storing "United States" but also "US" + // needs a migration to iso country code, for now, catch the latter (only 1 user via api) - echo ''; + echo ''; - } - + } + - } else echo ''; + } else echo ''; - ?> - - + + - - + + '; + // 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 '
'; + if ($value !== -99 && $value == $opt) echo ' checked="checked"'; + echo ' />
'; - $optIndex++; + $optIndex++; - } + } - } else echo ''; // + } else 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 '
'; + echo '
'; - $optIndex++; + $optIndex++; - } + } - } else echo ''; + } else echo ''; - ?> -
- - +
+ + - - + 0){ + // if got em + if (isset($zbsTaxRateTable) && is_array($zbsTaxRateTable) && count($zbsTaxRateTable) > 0){ - // if $default, use that - $selectVal = ''; - if ($value !== -99 && !empty($value)){ - $selectVal = $value; - } elseif (!empty($default)) - $selectVal = $default; + // if $default, use that + $selectVal = ''; + if ($value !== -99 && !empty($value)){ + $selectVal = $value; + } elseif (!empty($default)) + $selectVal = $default; - //catcher - echo ''; + //catcher + echo ''; - foreach ($zbsTaxRateTable as $taxRate){ + foreach ($zbsTaxRateTable as $taxRate){ - echo ''; + echo ''; - } + } - } else echo ''; + } else echo ''; - ?> - - - + + + name - $ret = $zbsTransactionFields[$colKey][1]; + // all fields (inc custom:) + if ( isset( $zbsTransactionFields ) && is_array( $zbsTransactionFields ) && isset( $zbsTransactionFields[ $colKey ] ) ) { - } - // all columns (any with same key will override) - if (isset($zeroBSCRM_columns_transaction['all']) && is_array($zeroBSCRM_columns_transaction['all']) && isset($zeroBSCRM_columns_transaction['all'][$colKey])){ + // key => name + $ret = $zbsTransactionFields[ $colKey ][1]; - // key => name - $ret = $zeroBSCRM_columns_transaction['all'][$colKey][0]; + } + // all columns (any with same key will override) + if ( isset( $zeroBSCRM_columns_transaction['all'] ) && is_array( $zeroBSCRM_columns_transaction['all'] ) && isset( $zeroBSCRM_columns_transaction['all'][ $colKey ] ) ) { - } + // key => name + $ret = $zeroBSCRM_columns_transaction['all'][ $colKey ][0]; - return $ret; } + return $ret; +} + // Temp here - takes a potential transaction column + returns html // these are mimics of js draw funcs, move into globals (eventually) // hacky at best... (WH wrote to quickly satisfy Borge freelance) - function zeroBS_objDraw_transactionColumnTD($colKey='',$obj=false){ +function zeroBS_objDraw_transactionColumnTD( $colKey = '', $obj = false ) { - $ret = ''; + $ret = ''; - if (!empty($colKey) && is_array($obj)){ + if ( ! empty( $colKey ) && is_array( $obj ) ) { - $linkOpen = jpcrm_esc_link('edit',$obj['id'],ZBS_TYPE_TRANSACTION); + $linkOpen = jpcrm_esc_link( 'edit', $obj['id'], ZBS_TYPE_TRANSACTION ); - switch ($colKey){ + switch ( $colKey ) { - case 'id': - $idRef = zeroBS_objDraw_generic_id($obj); - if (isset($obj['ref'])){ - if (!empty($idRef)) $idRef .= ' - '; - $idRef .= $obj['ref']; - } - $ret = ''. $idRef .''; - $ret .= !empty($obj['title']) ? '
'.$obj['title'] : ''; - break; - case 'editlink': - $ret = ''. __('Edit','zero-bs-crm') . ""; - break; - case 'date': + case 'id': + $idRef = zeroBS_objDraw_generic_id( $obj ); + if ( isset( $obj['ref'] ) ) { + if ( ! empty( $idRef ) ) { + $idRef .= ' - '; + } + $idRef .= $obj['ref']; + } + $ret = '' . $idRef . ''; + $ret .= ! empty( $obj['title'] ) ? '
' . $obj['title'] : ''; + break; + case 'editlink': + $ret = '' . __( 'Edit', 'zero-bs-crm' ) . ''; + break; + case 'date': if ( isset( $obj['date_date'] ) ) { $ret = $obj['date_date']; } - break; - case 'item': - $itemStr = ''; - if (isset($obj['meta'])) $itemStr = $obj['meta']['item']; // <3.0 - if (isset($obj['title'])) $itemStr = $obj['title']; // 3.0 - $ret = '' . $itemStr . ""; - break; - case 'total': - $total = 0; - if (isset($obj['meta'])) $total = $obj['meta']['total']; // <3.0 - if (isset($obj['total'])) $total = $obj['total']; // 3.0 - $ret = zeroBSCRM_formatCurrency($total); - break; - case 'status': - $status = ''; - if (isset($obj['meta'])) $status = $obj['meta']['status']; // <3.0 - if (isset($obj['status'])) $status = $obj['status']; // 3.0 - $ret = "" . ucfirst($status) . ""; - break; - + break; + case 'item': + $itemStr = ''; + if ( isset( $obj['meta'] ) ) { + $itemStr = $obj['meta']['item']; // <3.0 } + if ( isset( $obj['title'] ) ) { + $itemStr = $obj['title']; // 3.0 + } + $ret = '' . $itemStr . ''; + break; + case 'total': + $total = 0; + if ( isset( $obj['meta'] ) ) { + $total = $obj['meta']['total']; // <3.0 + } + if ( isset( $obj['total'] ) ) { + $total = $obj['total']; // 3.0 + } + $ret = zeroBSCRM_formatCurrency( $total ); + break; + case 'status': + $status = ''; + if ( isset( $obj['meta'] ) ) { + $status = $obj['meta']['status']; // <3.0 + } + if ( isset( $obj['status'] ) ) { + $status = $obj['status']; // 3.0 + } + $ret = "" . ucfirst( $status ) . ''; + break; - // if still empty, let's try generic text - if (empty($ret)) $ret = zeroBS_objDraw_generic_text($colKey,$obj); - - } + } - return $ret; + // if still empty, let's try generic text + if ( empty( $ret ) ) { + $ret = zeroBS_objDraw_generic_text( $colKey, $obj ); + } } + return $ret; +} + // Temp here // these are mimics of js draw funcs, move into globals (eventually) - function zeroBS_objDraw_generic_id($obj=false){ - - $ret = ''; +function zeroBS_objDraw_generic_id( $obj = false ) { - if (is_array($obj)){ + $ret = ''; - if (isset($obj['id'])) $ret = '#'.$obj['id']; - if (isset($obj['zbsid'])) $ret = '#'.$obj['zbsid']; - + if ( is_array( $obj ) ) { - } - - return $ret; + if ( isset( $obj['id'] ) ) { + $ret = '#' . $obj['id']; + } + if ( isset( $obj['zbsid'] ) ) { + $ret = '#' . $obj['zbsid']; + } } - function zeroBS_objDraw_generic_text($key='',$obj=false){ - - $ret = ''; - if (!empty($key) && is_array($obj)){ + return $ret; +} +function zeroBS_objDraw_generic_text( $key = '', $obj = false ) { - if (isset($obj[$key])) $ret = $obj[$key]; - if (isset($obj['meta']) && is_array($obj['meta']) && isset($obj['meta'][$key])) $ret = $obj['meta'][$key]; + $ret = ''; - } + if ( ! empty( $key ) && is_array( $obj ) ) { - return $ret; + if ( isset( $obj[ $key ] ) ) { + $ret = $obj[ $key ]; + } + if ( isset( $obj['meta'] ) && is_array( $obj['meta'] ) && isset( $obj['meta'][ $key ] ) ) { + $ret = $obj['meta'][ $key ]; + } } + return $ret; +} -/* ====================================================== - / Table Views (temporary) - ====================================================== */ - - // quick workaround to turn 29999 into 2.99.99 - // noting that the real issue here is our non delimited migration numbers :facepalm: - function zeroBSCRM_format_migrationVersion($ver=''){ - - // catch 3000 - $ver = str_replace( '000', '0', $ver); - - switch ( strlen( $ver) ){ - - // catch x.x - case 2: - $migrationName = substr($ver,0,1).'.'.substr($ver,1,1); - break; - // catch x.x.x - case 3: - $migrationName = substr($ver,0,1).'.'.substr($ver,1,1).'.'.substr($ver,2); - break; - case 4: - - // if second char is 0 - if ( substr( $ver, 1, 1 ) == 0 ){ +/* +====================================================== + / Table Views (temporary) + ====================================================== */ - // e.g. 3010 = 3.0.10 - $migrationName = substr($ver,0,1).'.'.substr($ver,1,1).'.'.substr($ver,2); + // quick workaround to turn 29999 into 2.99.99 + // noting that the real issue here is our non delimited migration numbers :facepalm: +function zeroBSCRM_format_migrationVersion( $ver = '' ) { + // catch 3000 + $ver = str_replace( '000', '0', $ver ); - } else { + switch ( strlen( $ver ) ) { - // e.g. 3111 = 3.11.1 - $migrationName = substr($ver,0,1).'.'.substr($ver,1,2).'.'.substr($ver,3); + // catch x.x + case 2: + $migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 1 ); + break; + // catch x.x.x + case 3: + $migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 1 ) . '.' . substr( $ver, 2 ); + break; + case 4: + // if second char is 0 + if ( substr( $ver, 1, 1 ) == 0 ) { - } + // e.g. 3010 = 3.0.10 + $migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 1 ) . '.' . substr( $ver, 2 ); + } else { - break; + // e.g. 3111 = 3.11.1 + $migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 2 ) . '.' . substr( $ver, 3 ); - // catch edge case 29999 - case 5: + } - // e.g. 29999 = 2.99 - $migrationName = substr($ver,0,1).'.'.substr($ver,1,2); + break; - break; + // catch edge case 29999 + case 5: + // e.g. 29999 = 2.99 + $migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 2 ); - // - default: - $migrationName = $ver; - break; + break; + default: + $migrationName = $ver; + break; - } + } - return $migrationName; - - } + return $migrationName; +} diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Forms.php b/projects/plugins/crm/includes/ZeroBSCRM.Forms.php index 3c44cb84570e..bbc4114e67da 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Forms.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Forms.php @@ -1,5 +1,5 @@ - 'true', - 'style' => 'simple' - ), $atts ) ); + extract( + shortcode_atts( + array( + 'id' => 'true', + 'style' => 'simple', + ), + $atts + ) + ); // force enquement zeroBSCRM_forms_enqueuements(); // return the form html - return zeroBSCRM_forms_build_form_html($atts['id'],$atts['style'],__('CRM Forms: You have not entered a style in your form shortcode','zero-bs-crm')); - + return zeroBSCRM_forms_build_form_html( $atts['id'], $atts['style'], __( 'CRM Forms: You have not entered a style in your form shortcode', 'zero-bs-crm' ) ); } -add_shortcode('jetpackcrm_form','zeroBSCRM_forms_shortcode'); -add_shortcode('zbs_form','zeroBSCRM_forms_shortcode'); +add_shortcode( 'jetpackcrm_form', 'zeroBSCRM_forms_shortcode' ); +add_shortcode( 'zbs_form', 'zeroBSCRM_forms_shortcode' ); + +function zeroBSCRM_forms_enqueuements() { -function zeroBSCRM_forms_enqueuements(){ + #} Assets we need specifically here - #} Assets we need specifically here - - // js - wp_enqueue_script("jquery"); - wp_enqueue_script('zbsfrontendformsjs'); - - // css - wp_enqueue_style('zbsfrontendformscss'); + // js + wp_enqueue_script( 'jquery' ); + wp_enqueue_script( 'zbsfrontendformsjs' ); + // css + wp_enqueue_style( 'zbsfrontendformscss' ); } // Register Forms widget class ZBS_Form_Widget extends WP_Widget { - - /** - * Register widget with WordPress. - */ - public function __construct() { - parent::__construct( - 'zbs_form_widget', // Base ID - 'Jetpack CRM Forms', // Name - array( 'description' => __( 'Embed a lead capture form to your website', 'zero-bs-crm' ), ) // Args - ); - } - + + /** + * Register widget with WordPress. + */ + public function __construct() { + parent::__construct( + 'zbs_form_widget', // Base ID + 'Jetpack CRM Forms', // Name + array( 'description' => __( 'Embed a lead capture form to your website', 'zero-bs-crm' ) ) // Args + ); + } + /** * Front-end display of widget. * @@ -117,94 +118,96 @@ public function widget( $args, $instance ) { } echo $args['after_widget']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } - - /** - * Back-end widget form. - * - * @see WP_Widget::form() - * - * @param array $instance Previously saved values from database. + + /** + * Back-end widget form. + * + * @see WP_Widget::form() + * + * @param array $instance Previously saved values from database. * @return string|void - */ - 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; - } - ?> -

- - -

+ */ + 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 +216,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 +265,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 +156,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 +196,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 +278,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 +297,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 +601,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 +671,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 +760,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 +833,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 +1031,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 +1280,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 +1307,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 +1317,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 +1338,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 +1392,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 +1459,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 +1526,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 +1546,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.IntegrationFuncs.php b/projects/plugins/crm/includes/ZeroBSCRM.IntegrationFuncs.php index e3d03e84df32..f2291c8ee3cd 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.IntegrationFuncs.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.IntegrationFuncs.php @@ -1,5 +1,5 @@ - 'woodyhayday2@smt.com', - - 'zbsc_status' => 'Lead', - 'zbsc_prefix' => 'Mr', - 'zbsc_fname' => 'Woody', - 'zbsc_lname' => 'Hayday', - 'zbsc_addr1' => 'First Addr', - 'zbsc_addr2' => '2nd Addr', - 'zbsc_city' => 'London', - 'zbsc_county' => 'G London', - 'zbsc_postcode' => 'AL1 111', - 'zbsc_hometel' => '0123456789', - 'zbsc_worktel' => '999', - 'zbsc_mobtel' => '333', - 'zbsc_notes' => 'Multi Line - Notes - Kick Ass', - - #} custom fields are set as cf(int) and so are per-install dependent, you probs don't ever want to insert these :) :D - #'zbsc_cf1' => 'Google' - - ), + 'zbsc_email' => 'woodyhayday2@smt.com', + + 'zbsc_status' => 'Lead', + 'zbsc_prefix' => 'Mr', + 'zbsc_fname' => 'Woody', + 'zbsc_lname' => 'Hayday', + 'zbsc_addr1' => 'First Addr', + 'zbsc_addr2' => '2nd Addr', + 'zbsc_city' => 'London', + 'zbsc_county' => 'G London', + 'zbsc_postcode' => 'AL1 111', + 'zbsc_hometel' => '0123456789', + 'zbsc_worktel' => '999', + 'zbsc_mobtel' => '333', + 'zbsc_notes' => 'Multi Line + Notes + Kick Ass', + + #} custom fields are set as cf(int) and so are per-install dependent, you probs don't ever want to insert these :) :D + #'zbsc_cf1' => 'Google' + + ), 'customer_date as per mike!', - 'none', + 'none', - false, + false, false - ); - + ); + | | ... note "woo" external source flag | ... note "woodyhayday2@smt.com" - my ID within woo @@ -122,196 +119,188 @@ function zeroBS_integrations_getCustomer($externalSource='',$externalID=''){ | ... Note: From v1.1.18 we also have fallback logs: | -------------------------------------------------- | Fallback Logs: - | Pass either: - | 'none' = do nothing if user already exists - | 'auto' = automatically create log (NOT WORKING YET) - | OR: - | array( - | 'type' => 'Form Filled',#'form_filled', - | 'shortdesc' => 'Dude filled out the form x on y', - | 'longdesc' => '' - | ) - | - | (Long desc is optional) - | - | #} CURRENT Note Types (use first field/key e.g. "form_filled") (v1.1.18 - 20/09/16) - | - | 'note': { label: 'Note', ico: 'fa-sticky-note-o' }, - | 'call': { label: 'Call', ico: 'fa-phone-square' }, - | 'email': { label: 'Email', ico: 'fa-envelope-o' }, - | 'meeting': { label: 'Meeting', ico: 'fa-users' }, - | 'quote__sent': { label: 'Quote: Sent', ico: 'fa-share-square-o' }, - | 'quote__accepted': { label: 'Quote: Accepted', ico: 'fa-thumbs-o-up' }, - | 'quote__refused': { label: 'Quote: Refused', ico: 'fa-ban' }, - | 'invoice__sent': { label: 'Invoice: Sent', ico: 'fa-share-square-o' }, - | 'invoice__part_paid': { label: 'Invoice: Part Paid', ico: 'fa-money' }, - | 'invoice__paid': { label: 'Invoice: Paid', ico: 'fa-money' }, - | 'invoice__refunded': { label: 'Invoice: Refunded', ico: 'fa-money' }, - | 'transaction': { label: 'Transaction', ico: 'fa-credit-card' }, - | 'tweet': { label: 'Tweet', ico: 'fa-twitter' }, - | 'facebook_post': { label: 'Facebook Post', ico: 'fa-facebook-official' }, - | 'created': { label: 'Created', ico: 'fa-plus-circle' }, - | 'updated': { label: 'Updated', ico: 'fa-pencil-square-o' }, - | 'quote_created': { label: 'Quote Created', ico: 'fa-plus-circle' }, - | 'invoice_created': { label: 'Invoice Created', ico: 'fa-plus-circle' }, - | 'form_filled': { label: 'Form Filled', ico: 'fa-wpforms'} + | Pass either: + | 'none' = do nothing if user already exists + | 'auto' = automatically create log (NOT WORKING YET) + | OR: + | array( + | 'type' => 'Form Filled',#'form_filled', + | 'shortdesc' => 'Dude filled out the form x on y', + | 'longdesc' => '' + | ) + | + | (Long desc is optional) + | + | #} CURRENT Note Types (use first field/key e.g. "form_filled") (v1.1.18 - 20/09/16) + | + | 'note': { label: 'Note', ico: 'fa-sticky-note-o' }, + | 'call': { label: 'Call', ico: 'fa-phone-square' }, + | 'email': { label: 'Email', ico: 'fa-envelope-o' }, + | 'meeting': { label: 'Meeting', ico: 'fa-users' }, + | 'quote__sent': { label: 'Quote: Sent', ico: 'fa-share-square-o' }, + | 'quote__accepted': { label: 'Quote: Accepted', ico: 'fa-thumbs-o-up' }, + | 'quote__refused': { label: 'Quote: Refused', ico: 'fa-ban' }, + | 'invoice__sent': { label: 'Invoice: Sent', ico: 'fa-share-square-o' }, + | 'invoice__part_paid': { label: 'Invoice: Part Paid', ico: 'fa-money' }, + | 'invoice__paid': { label: 'Invoice: Paid', ico: 'fa-money' }, + | 'invoice__refunded': { label: 'Invoice: Refunded', ico: 'fa-money' }, + | 'transaction': { label: 'Transaction', ico: 'fa-credit-card' }, + | 'tweet': { label: 'Tweet', ico: 'fa-twitter' }, + | 'facebook_post': { label: 'Facebook Post', ico: 'fa-facebook-official' }, + | 'created': { label: 'Created', ico: 'fa-plus-circle' }, + | 'updated': { label: 'Updated', ico: 'fa-pencil-square-o' }, + | 'quote_created': { label: 'Quote Created', ico: 'fa-plus-circle' }, + | 'invoice_created': { label: 'Invoice Created', ico: 'fa-plus-circle' }, + | 'form_filled': { label: 'Form Filled', ico: 'fa-wpforms'} | | -------------------------------------------------- | | | - | #} RE: $extraMeta (This isn't used anywhere yet, talk to WH before using) + | #} RE: $extraMeta (This isn't used anywhere yet, talk to WH before using) | - | ... this is a key value array passable to add extra values to customers - | ... should look like: + | ... this is a key value array passable to add extra values to customers + | ... should look like: | - | $extraMeta = array( + | $extraMeta = array( | - | array('key_here',12345), - | array('another','what') + | array('key_here',12345), + | array('another','what') | - | ) + | ) | - | ... which will add the following meta to a customer: + | ... which will add the following meta to a customer: | - | zbs_customer_extra_key_here = 12345 - | zbs_customer_extra_another = what + | zbs_customer_extra_key_here = 12345 + | zbs_customer_extra_another = what | - | ... BRUTALLY - no checking, just overwrites! (so be careful) + | ... BRUTALLY - no checking, just overwrites! (so be careful) | - | #} Re: $automatorPassthrough + | #} Re: $automatorPassthrough | - | ... adding anything here allows it to be passed through to the internal automator (which currently sets notes) - | ... this means you can pass an array with note str overrides... e.g. + | ... adding anything here allows it to be passed through to the internal automator (which currently sets notes) + | ... this means you can pass an array with note str overrides... e.g. | - | array( + | array( | - | 'note_override' => array( - | - | 'type' => 'Form Filled',#'form_filled', - | 'shortdesc' => 'Dude filled out the form x on y', - | 'longdesc' => '' + | 'note_override' => array( | - | ) + | 'type' => 'Form Filled',#'form_filled', + | 'shortdesc' => 'Dude filled out the form x on y', + | 'longdesc' => '' | - | ) + | ) | - | ... see recipes to see what's useful :) + | ) + | + | ... see recipes to see what's useful :) | |======================================= - | 27/09/16: $emailAlreadyExistsAction - | - | This is a flag to say what to do in this circumstance: User obj passed has an email (in $customerFields['zbsc_email']) which matches a customer in DB already - | ... options: - | 'update': Update customer record (and add external source) (BRUTAL override) - | 'skip': Do nothing - | 'notifyexit': quit + notify - | ... this func is mostly future proofing, as there may be times we want to avoid overriding existing data from an import e.g. + | 27/09/16: $emailAlreadyExistsAction + | + | This is a flag to say what to do in this circumstance: User obj passed has an email (in $customerFields['zbsc_email']) which matches a customer in DB already + | ... options: + | 'update': Update customer record (and add external source) (BRUTAL override) + | 'skip': Do nothing + | 'notifyexit': quit + notify + | ... this func is mostly future proofing, as there may be times we want to avoid overriding existing data from an import e.g. | |======================================= | ... Made this func super easy so you can just fire it when you're not sure if add or update... :) it'll deal. |======================================= | Returns: - | Customer ID - | or - | False (boolean) (customer create/update failed) + | Customer ID + | or + | False (boolean) (customer create/update failed) |======================================= */ -function zeroBS_integrations_addOrUpdateCustomer($externalSource='',$externalID='',$customerFields=array(), $customerDate = '', $fallbackLog='auto', $extraMeta = false, $automatorPassthroughArray = false, $emailAlreadyExistsAction = 'update',$fieldPrefix = 'zbsc_'){ +function zeroBS_integrations_addOrUpdateCustomer( $externalSource = '', $externalID = '', $customerFields = array(), $customerDate = '', $fallbackLog = 'auto', $extraMeta = false, $automatorPassthroughArray = false, $emailAlreadyExistsAction = 'update', $fieldPrefix = 'zbsc_' ) { #} leave this true and it'll run as normal. $usualUpdate = true; $potentialCustomerIDfromEmail = false; - if (!empty($externalSource) && !empty($externalID) && is_array($customerFields) && count($customerFields) > 0){ + if ( ! empty( $externalSource ) && ! empty( $externalID ) && is_array( $customerFields ) && count( $customerFields ) > 0 ) { - if (isset($customerFields['zbsc_email']) && !empty($customerFields['zbsc_email'])){ + if ( isset( $customerFields['zbsc_email'] ) && ! empty( $customerFields['zbsc_email'] ) ) { #} First check for email in cust list - $potentialCustomerIDfromEmail = zeroBS_getCustomerIDWithEmail($customerFields['zbsc_email']); + $potentialCustomerIDfromEmail = zeroBS_getCustomerIDWithEmail( $customerFields['zbsc_email'] ); #} If so... act based on $emailAlreadyExistsAction param - if (!empty($potentialCustomerIDfromEmail)){ + if ( ! empty( $potentialCustomerIDfromEmail ) ) { #} So we have a customer with this email... - switch ($emailAlreadyExistsAction){ + switch ( $emailAlreadyExistsAction ) { - /* not built out yet... + /* + not built out yet... case 'addextsrc': #} Just add the external source - break; */ case 'update': - #} Just let it roll on... $usualUpdate = true; break; case 'skip': - #} don't do nothin :) $usualUpdate = false; - break; case 'notifyexit': - #} Notify + exit echo esc_html( 'Contact Add/Update Issue: A contact already exists with the email "' . $customerFields['zbsc_email'] . '" (ID: ' . $potentialCustomerIDfromEmail . '), user could not be processed!' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase exit( 0 ); break; - - } - } - } #} ========================================================================================= #} NO existing user! Proceed as before! #} ========================================================================================= - if ($usualUpdate){ - + if ( $usualUpdate ) { // if ID specifically passed, use that :) - if (isset($customerFields['id']) && !empty($customerFields['id']) && $customerFields['id'] > 0){ + if ( isset( $customerFields['id'] ) && ! empty( $customerFields['id'] ) && $customerFields['id'] > 0 ) { $potentialCustomerID = $customerFields['id']; - + } else { #} Do query for ID - $potentialCustomerID = zeroBS_getCustomerIDWithExternalSource($externalSource,$externalID); + $potentialCustomerID = zeroBS_getCustomerIDWithExternalSource( $externalSource, $externalID ); } #} If ID empty, but $potentialCustomerIDfromEmail (from above) not, use $potentialCustomerIDfromEmail - if (($potentialCustomerID === false || $potentialCustomerID == -1) && $potentialCustomerIDfromEmail !== false) $potentialCustomerID = $potentialCustomerIDfromEmail; + if ( ( $potentialCustomerID === false || $potentialCustomerID == -1 ) && $potentialCustomerIDfromEmail !== false ) { + $potentialCustomerID = $potentialCustomerIDfromEmail; + } #} Default fallback log creation $fallbackLogToPass = false; - if ( - !isset($fallbackLog) || - !is_array($fallbackLog) - ) { + if ( + ! isset( $fallbackLog ) || + ! is_array( $fallbackLog ) + ) { #} create default fallback log, unless $fallbackLog is set to 'none' - if ($fallbackLog !== 'none'){ + if ( $fallbackLog !== 'none' ) { #} Autogen #} Left this out for v1.1.18... needs thought. - #} Do we really want to put "woo source added"? It might get added loads. + #} Do we really want to put "woo source added"? It might get added loads. #} For now leave as manual... } - - } elseif (is_array($fallbackLog)){ + } elseif ( is_array( $fallbackLog ) ) { #} Fallback log is probably set, just pass it along. $fallbackLogToPass = $fallbackLog; @@ -319,73 +308,74 @@ function zeroBS_integrations_addOrUpdateCustomer($externalSource='',$externalID= } #} Here we're passing along any automator pass through - #} ... which will typically be overrides for creation logs or any extra params to give to internal automator. - $automatorPassthrough = false; if (isset($automatorPassthroughArray) && is_array($automatorPassthroughArray)) $automatorPassthrough = $automatorPassthroughArray; + #} ... which will typically be overrides for creation logs or any extra params to give to internal automator. + $automatorPassthrough = false; + if ( isset( $automatorPassthroughArray ) && is_array( $automatorPassthroughArray ) ) { + $automatorPassthrough = $automatorPassthroughArray; + } #} Not yet used, ask WH // Now passing through 2.24+ $extraMeta = false; #} Brutal add/update #} MS - 3rd Jan 2019 - this (eventually) just calls the usual _addUpdateCustomer function - $customerID = zeroBS_addUpdateCustomer($potentialCustomerID,$customerFields,$externalSource,$externalID, $customerDate, $fallbackLogToPass, $extraMeta, $automatorPassthrough, -1, $fieldPrefix); + $customerID = zeroBS_addUpdateCustomer( $potentialCustomerID, $customerFields, $externalSource, $externalID, $customerDate, $fallbackLogToPass, $extraMeta, $automatorPassthrough, -1, $fieldPrefix ); return $customerID; - } #} / usual update - } else{ + } else { return false; } - } /* |======================================= - | zeroBS_integrations_addOrUpdateCompany + | zeroBS_integrations_addOrUpdateCompany |======================================= | Add's a new Company, or updates an existing Company, where their externalSource + externalID matches an existing Company (if specified) | NOTE: This is different from zeroBS_integrations_addOrUpdateCustomer, in that the externalID must be COMPANY NAME | This only works with specific external sources, as 'zeroBS_integrations_getCompany' | These "externalSource"s can be flags we agree on, and add here for reference - | 23/01/2015: - | 'woo' = WooCommerce - | 'pay' = Paypal - | 'form' = Form Capture + | 23/01/2015: + | 'woo' = WooCommerce + | 'pay' = Paypal + | 'form' = Form Capture | | Usage: - + zeroBS_integrations_addOrUpdateCompany('woo','Dell',array( - 'zbsc_coname' => 'Dell', + 'zbsc_coname' => 'Dell', - 'zbsc_status' => 'Lead', - 'zbsc_addr1' => 'First Addr', - 'zbsc_addr2' => '2nd Addr', - 'zbsc_city' => 'London', - 'zbsc_county' => 'G London', - 'zbsc_postcode' => 'AL1 111', - 'zbsc_hometel' => '0123456789', - 'zbsc_worktel' => '999', - 'zbsc_mobtel' => '333', - 'zbsc_notes' => 'Multi Line - Notes - Kick Ass', + 'zbsc_status' => 'Lead', + 'zbsc_addr1' => 'First Addr', + 'zbsc_addr2' => '2nd Addr', + 'zbsc_city' => 'London', + 'zbsc_county' => 'G London', + 'zbsc_postcode' => 'AL1 111', + 'zbsc_hometel' => '0123456789', + 'zbsc_worktel' => '999', + 'zbsc_mobtel' => '333', + 'zbsc_notes' => 'Multi Line + Notes + Kick Ass', - #} custom fields are set as cf(int) and so are per-install dependent, you probs don't ever want to insert these :) :D - #'zbsc_cf1' => 'Google' + #} custom fields are set as cf(int) and so are per-install dependent, you probs don't ever want to insert these :) :D + #'zbsc_cf1' => 'Google' - ), + ), 'customer_date as per mike!', - 'none', + 'none', - false, + false, false - ); - + ); + | | ... note "woo" external source flag | ... note "woodyhayday2@smt.com" - my ID within woo @@ -394,207 +384,204 @@ function zeroBS_integrations_addOrUpdateCustomer($externalSource='',$externalID= | ... Note: From v1.1.18 we also have fallback logs: | -------------------------------------------------- | Fallback Logs: - | Pass either: - | 'none' = do nothing if user already exists - | 'auto' = automatically create log (NOT WORKING YET) - | OR: - | array( - | 'type' => 'Form Filled',#'form_filled', - | 'shortdesc' => 'Dude filled out the form x on y', - | 'longdesc' => '' - | ) - | - | (Long desc is optional) - | - | #} CURRENT Note Types (use first field/key e.g. "form_filled") (v1.1.18 - 20/09/16) - | - | 'note': { label: 'Note', ico: 'fa-sticky-note-o' }, - | 'call': { label: 'Call', ico: 'fa-phone-square' }, - | 'email': { label: 'Email', ico: 'fa-envelope-o' }, - | 'meeting': { label: 'Meeting', ico: 'fa-users' }, - | 'quote__sent': { label: 'Quote: Sent', ico: 'fa-share-square-o' }, - | 'quote__accepted': { label: 'Quote: Accepted', ico: 'fa-thumbs-o-up' }, - | 'quote__refused': { label: 'Quote: Refused', ico: 'fa-ban' }, - | 'invoice__sent': { label: 'Invoice: Sent', ico: 'fa-share-square-o' }, - | 'invoice__part_paid': { label: 'Invoice: Part Paid', ico: 'fa-money' }, - | 'invoice__paid': { label: 'Invoice: Paid', ico: 'fa-money' }, - | 'invoice__refunded': { label: 'Invoice: Refunded', ico: 'fa-money' }, - | 'transaction': { label: 'Transaction', ico: 'fa-credit-card' }, - | 'tweet': { label: 'Tweet', ico: 'fa-twitter' }, - | 'facebook_post': { label: 'Facebook Post', ico: 'fa-facebook-official' }, - | 'created': { label: 'Created', ico: 'fa-plus-circle' }, - | 'updated': { label: 'Updated', ico: 'fa-pencil-square-o' }, - | 'quote_created': { label: 'Quote Created', ico: 'fa-plus-circle' }, - | 'invoice_created': { label: 'Invoice Created', ico: 'fa-plus-circle' }, - | 'form_filled': { label: 'Form Filled', ico: 'fa-wpforms'} + | Pass either: + | 'none' = do nothing if user already exists + | 'auto' = automatically create log (NOT WORKING YET) + | OR: + | array( + | 'type' => 'Form Filled',#'form_filled', + | 'shortdesc' => 'Dude filled out the form x on y', + | 'longdesc' => '' + | ) + | + | (Long desc is optional) + | + | #} CURRENT Note Types (use first field/key e.g. "form_filled") (v1.1.18 - 20/09/16) + | + | 'note': { label: 'Note', ico: 'fa-sticky-note-o' }, + | 'call': { label: 'Call', ico: 'fa-phone-square' }, + | 'email': { label: 'Email', ico: 'fa-envelope-o' }, + | 'meeting': { label: 'Meeting', ico: 'fa-users' }, + | 'quote__sent': { label: 'Quote: Sent', ico: 'fa-share-square-o' }, + | 'quote__accepted': { label: 'Quote: Accepted', ico: 'fa-thumbs-o-up' }, + | 'quote__refused': { label: 'Quote: Refused', ico: 'fa-ban' }, + | 'invoice__sent': { label: 'Invoice: Sent', ico: 'fa-share-square-o' }, + | 'invoice__part_paid': { label: 'Invoice: Part Paid', ico: 'fa-money' }, + | 'invoice__paid': { label: 'Invoice: Paid', ico: 'fa-money' }, + | 'invoice__refunded': { label: 'Invoice: Refunded', ico: 'fa-money' }, + | 'transaction': { label: 'Transaction', ico: 'fa-credit-card' }, + | 'tweet': { label: 'Tweet', ico: 'fa-twitter' }, + | 'facebook_post': { label: 'Facebook Post', ico: 'fa-facebook-official' }, + | 'created': { label: 'Created', ico: 'fa-plus-circle' }, + | 'updated': { label: 'Updated', ico: 'fa-pencil-square-o' }, + | 'quote_created': { label: 'Quote Created', ico: 'fa-plus-circle' }, + | 'invoice_created': { label: 'Invoice Created', ico: 'fa-plus-circle' }, + | 'form_filled': { label: 'Form Filled', ico: 'fa-wpforms'} | | -------------------------------------------------- | | | - | #} RE: $extraMeta (This isn't used anywhere yet, talk to WH before using) + | #} RE: $extraMeta (This isn't used anywhere yet, talk to WH before using) + | + | ... this is a key value array passable to add extra values to customers + | ... should look like: | - | ... this is a key value array passable to add extra values to customers - | ... should look like: + | $extraMeta = array( | - | $extraMeta = array( + | array('key_here',12345), + | array('another','what') | - | array('key_here',12345), - | array('another','what') + | ) | - | ) + | ... which will add the following meta to a customer: | - | ... which will add the following meta to a customer: + | zbs_customer_extra_key_here = 12345 + | zbs_customer_extra_another = what | - | zbs_customer_extra_key_here = 12345 - | zbs_customer_extra_another = what + | ... BRUTALLY - no checking, just overwrites! (so be careful) | - | ... BRUTALLY - no checking, just overwrites! (so be careful) + | #} Re: $automatorPassthrough | - | #} Re: $automatorPassthrough + | ... adding anything here allows it to be passed through to the intval(var)ternal automator (which currently sets notes) + | ... this means you can pass an array with note str overrides... e.g. | - | ... adding anything here allows it to be passed through to the intval(var)ternal automator (which currently sets notes) - | ... this means you can pass an array with note str overrides... e.g. + | array( | - | array( + | 'note_override' => array( | - | 'note_override' => array( - | - | 'type' => 'Form Filled',#'form_filled', - | 'shortdesc' => 'Dude filled out the form x on y', - | 'longdesc' => '' + | 'type' => 'Form Filled',#'form_filled', + | 'shortdesc' => 'Dude filled out the form x on y', + | 'longdesc' => '' | - | ) + | ) | - | ) + | ) | - | ... see recipes to see what's useful :) + | ... see recipes to see what's useful :) | |======================================= - | 27/09/16: $conameAlreadyExistsAction - | - | This is a flag to say what to do in this circumstance: User obj passed has an email (in $companyFields['zbsc_coname']) which matches a company in DB already - | ... options: - | 'update': Update company record (and add external source) (BRUTAL override) - | 'skip': Do nothing - | 'notifyexit': quit + notify - | ... this func is mostly future proofing, as there may be times we want to avoid overriding existing data from an import e.g. + | 27/09/16: $conameAlreadyExistsAction + | + | This is a flag to say what to do in this circumstance: User obj passed has an email (in $companyFields['zbsc_coname']) which matches a company in DB already + | ... options: + | 'update': Update company record (and add external source) (BRUTAL override) + | 'skip': Do nothing + | 'notifyexit': quit + notify + | ... this func is mostly future proofing, as there may be times we want to avoid overriding existing data from an import e.g. | |======================================= | ... Made this func super easy so you can just fire it when you're not sure if add or update... :) it'll deal. |======================================= | Returns: - | Company ID - | or - | False (boolean) (Company create/update failed) + | Company ID + | or + | False (boolean) (Company create/update failed) |======================================= */ #} External source + (externalID = Co NAME) function zeroBS_integrations_addOrUpdateCompany( - $externalSource='', - $externalID='', - $companyFields=array(), - $companyDate = '', - $fallbackLog='auto', - $extraMeta = false, - $automatorPassthroughArray = false, + $externalSource = '', + $externalID = '', + $companyFields = array(), + $companyDate = '', + $fallbackLog = 'auto', + $extraMeta = false, + $automatorPassthroughArray = false, $conameAlreadyExistsAction = 'update', - $fieldPrefix = 'zbsc_'){ + $fieldPrefix = 'zbsc_' +) { global $zbs; #} leave this true and it'll run as normal. $usualUpdate = true; - if (!empty($externalSource) && !empty($externalID) && is_array($companyFields) && count($companyFields) > 0){ + if ( ! empty( $externalSource ) && ! empty( $externalID ) && is_array( $companyFields ) && count( $companyFields ) > 0 ) { $potentialCompanyIDfromName = false; - $potentialCoName = ''; + $potentialCoName = ''; // <3.0 - if (isset($companyFields[$fieldPrefix.'coname']) && !empty($companyFields[$fieldPrefix.'coname'])) $potentialCoName = $companyFields[$fieldPrefix.'coname']; + if ( isset( $companyFields[ $fieldPrefix . 'coname' ] ) && ! empty( $companyFields[ $fieldPrefix . 'coname' ] ) ) { + $potentialCoName = $companyFields[ $fieldPrefix . 'coname' ]; + } // 3.0 - if (isset($companyFields[$fieldPrefix.'name']) && !empty($companyFields[$fieldPrefix.'name'])) $potentialCoName = $companyFields[$fieldPrefix.'name']; - + if ( isset( $companyFields[ $fieldPrefix . 'name' ] ) && ! empty( $companyFields[ $fieldPrefix . 'name' ] ) ) { + $potentialCoName = $companyFields[ $fieldPrefix . 'name' ]; + } - if ($potentialCoName !== ''){ + if ( $potentialCoName !== '' ) { #} First check for name in company list - $potentialCompanyIDfromName = zeroBS_getCompanyIDWithName($potentialCoName); + $potentialCompanyIDfromName = zeroBS_getCompanyIDWithName( $potentialCoName ); #} If so... act based on $conameAlreadyExistsAction param - if (!empty($potentialCompanyIDfromName)){ + if ( ! empty( $potentialCompanyIDfromName ) ) { #} So we have a customer with this email... - switch ($conameAlreadyExistsAction){ + switch ( $conameAlreadyExistsAction ) { - /* not built out yet... + /* + not built out yet... case 'addextsrc': #} Just add the external source - break; */ case 'update': - #} Just let it roll on... $usualUpdate = true; break; case 'skip': - #} don't do nothin :) $usualUpdate = false; - break; case 'notifyexit': - #} Notify + exit - echo esc_html( __(jpcrm_label_company().' Add/Update Issue: A '.jpcrm_label_company().' already exists with the name "','zero-bs-crm').$potentialCoName.'" (ID: '.$potentialCompanyIDfromName.'), '.__('could not be processed!','zero-bs-crm') ); + echo esc_html( __( jpcrm_label_company() . ' Add/Update Issue: A ' . jpcrm_label_company() . ' already exists with the name "', 'zero-bs-crm' ) . $potentialCoName . '" (ID: ' . $potentialCompanyIDfromName . '), ' . __( 'could not be processed!', 'zero-bs-crm' ) ); exit( 0 ); break; - - } - } - } #} ========================================================================================= #} NO existing user! Proceed as before! #} ========================================================================================= - if ($usualUpdate){ + if ( $usualUpdate ) { #} Do query for ID - $potentialCompanyID = zeroBS_getCompanyIDWithExternalSource($externalSource,$externalID); + $potentialCompanyID = zeroBS_getCompanyIDWithExternalSource( $externalSource, $externalID ); #} If ID empty, but $potentialCompanyIDfromName (from above) not, use $potentialCompanyIDfromName - if ($potentialCompanyID === false && $potentialCompanyIDfromName !== false) $potentialCompanyID = $potentialCompanyIDfromName; + if ( $potentialCompanyID === false && $potentialCompanyIDfromName !== false ) { + $potentialCompanyID = $potentialCompanyIDfromName; + } #} Default fallback log creation $fallbackLogToPass = false; - if ( - !isset($fallbackLog) || - !is_array($fallbackLog) - ) { + if ( + ! isset( $fallbackLog ) || + ! is_array( $fallbackLog ) + ) { #} create default fallback log, unless $fallbackLog is set to 'none' - if ($fallbackLog !== 'none'){ + if ( $fallbackLog !== 'none' ) { #} Autogen #} Left this out for v1.1.18... needs thought. - #} Do we really want to put "woo source added"? It might get added loads. + #} Do we really want to put "woo source added"? It might get added loads. #} For now leave as manual... } - - } elseif (is_array($fallbackLog)){ + } elseif ( is_array( $fallbackLog ) ) { #} Fallback log is probably set, just pass it along. $fallbackLogToPass = $fallbackLog; @@ -602,29 +589,30 @@ function zeroBS_integrations_addOrUpdateCompany( } #} Here we're passing along any automator pass through - #} ... which will typically be overrides for creation logs or any extra params to give to internal automator. - $automatorPassthrough = false; if (isset($automatorPassthroughArray) && is_array($automatorPassthroughArray)) $automatorPassthrough = $automatorPassthroughArray; + #} ... which will typically be overrides for creation logs or any extra params to give to internal automator. + $automatorPassthrough = false; + if ( isset( $automatorPassthroughArray ) && is_array( $automatorPassthroughArray ) ) { + $automatorPassthrough = $automatorPassthroughArray; + } #} Not yet used, ask WH $extraMeta = false; #} Brutal add/update - $companyID = zeroBS_addUpdateCompany($potentialCompanyID,$companyFields,$externalSource,$externalID, $companyDate, $fallbackLogToPass, $extraMeta, $automatorPassthrough,-1,$fieldPrefix); + $companyID = zeroBS_addUpdateCompany( $potentialCompanyID, $companyFields, $externalSource, $externalID, $companyDate, $fallbackLogToPass, $extraMeta, $automatorPassthrough, -1, $fieldPrefix ); return $companyID; - } #} / usual update - } else return false; - - + } else { + return false; + } } - /* |======================================= - | zeroBS_integrations_getCompany + | zeroBS_integrations_getCompany |======================================= | Retrieves a Company record (as usual _getCompany func) - but one that has been inserted via import from an external source | E.g. Woo Imported, Paypal imported, whatever @@ -635,49 +623,40 @@ function zeroBS_integrations_addOrUpdateCompany( | zeroBS_integrations_getCompany('pay','x3da9j3d9jad2') |======================================= | Returns: - | Company obj (std class) - | or - | False (boolean) (Company does not exist) + | Company obj (std class) + | or + | False (boolean) (Company does not exist) |======================================= | Check via: if ($coobj !== false) |======================================= */ -function zeroBS_integrations_getCompany($externalSource='',$externalID=''){ +function zeroBS_integrations_getCompany( $externalSource = '', $externalID = '' ) { #} Do query for ID - $potentialCompanyID = zeroBS_getCompanyIDWithExternalSource($externalSource,$externalID); + $potentialCompanyID = zeroBS_getCompanyIDWithExternalSource( $externalSource, $externalID ); - if ($potentialCompanyID !== false){ + if ( $potentialCompanyID !== false ) { #} If so, pass full deets via this - return zeroBS_getCompany($potentialCompanyID); + return zeroBS_getCompany( $potentialCompanyID ); } #} If it gets here, it failed return false; - } - - - - - - - - /* |======================================= - | zeroBS_integrations_addOrUpdateTransaction + | zeroBS_integrations_addOrUpdateTransaction |======================================= | Add's a new Transaction, or updates an existing Transaction, where their externalSource + externalID matches an existing Transaction (if specified) | NOTE: This is different from zeroBS_integrations_addOrUpdateCustomer, in that the externalID must be Transaction ID | This only works with specific external sources, as 'zeroBS_integrations_getTransaction' | Usage: - + zeroBS_integrations_addOrUpdateTransaction('woo','#123456',array( - + REQUIRED: 'orderid' => 'UNIQUEID', 'customer' => CustomerID, @@ -694,7 +673,6 @@ function zeroBS_integrations_getCompany($externalSource='',$externalID=''){ 'discount' => 0, 'tax_rate' => 0, - ), array( TAGS: 'sale','bill','chargeback','refund','echeckchargeback','cancel-rebill','uncancel-rebill' etc. @@ -703,14 +681,14 @@ function zeroBS_integrations_getCompany($externalSource='',$externalID=''){ 'date as per mike!', - 'none', + 'none', - false, + false, false - ); - + ); + | | ... note "woo" external source flag | ... note "woodyhayday2@smt.com" - my ID within woo @@ -719,151 +697,156 @@ function zeroBS_integrations_getCompany($externalSource='',$externalID=''){ | ... Note: From v1.1.18 we also have fallback logs: | -------------------------------------------------- | Fallback Logs: - | Pass either: - | 'none' = do nothing if user already exists - | 'auto' = automatically create log (NOT WORKING YET) - | OR: - | array( - | 'type' => 'Form Filled',#'form_filled', - | 'shortdesc' => 'Dude filled out the form x on y', - | 'longdesc' => '' - | ) - | - | (Long desc is optional) + | Pass either: + | 'none' = do nothing if user already exists + | 'auto' = automatically create log (NOT WORKING YET) + | OR: + | array( + | 'type' => 'Form Filled',#'form_filled', + | 'shortdesc' => 'Dude filled out the form x on y', + | 'longdesc' => '' + | ) + | + | (Long desc is optional) | | -------------------------------------------------- | | - | #} RE: $extraMeta + | #} RE: $extraMeta | - | ... this is a key value array passable to add extra values to customers - | ... should look like: + | ... this is a key value array passable to add extra values to customers + | ... should look like: | - | $extraMeta = array( + | $extraMeta = array( | - | array('key_here',12345), - | array('another','what') + | array('key_here',12345), + | array('another','what') | - | ) + | ) | - | ... which will add the following meta to a customer: + | ... which will add the following meta to a customer: | - | zbs_customer_extra_key_here = 12345 - | zbs_customer_extra_another = what + | zbs_customer_extra_key_here = 12345 + | zbs_customer_extra_another = what | - | ... BRUTALLY - no checking, just overwrites! (so be careful) + | ... BRUTALLY - no checking, just overwrites! (so be careful) | | -------------------------------------------------- | - | #} Re: $automatorPassthrough + | #} Re: $automatorPassthrough | - | ... adding anything here allows it to be passed through to the internal automator (which currently sets notes) - | ... this means you can pass an array with note str overrides... e.g. + | ... adding anything here allows it to be passed through to the internal automator (which currently sets notes) + | ... this means you can pass an array with note str overrides... e.g. | - | array( + | array( | - | 'note_override' => array( - | - | 'type' => 'Form Filled',#'form_filled', - | 'shortdesc' => 'Dude filled out the form x on y', - | 'longdesc' => '' + | 'note_override' => array( | - | ) + | 'type' => 'Form Filled',#'form_filled', + | 'shortdesc' => 'Dude filled out the form x on y', + | 'longdesc' => '' | - | ) + | ) | - | ... see recipes to see what's useful :) + | ) + | + | ... see recipes to see what's useful :) | |======================================= | Returns: - | Transaction ID - | or - | False (boolean) (Transaction create/update failed) + | Transaction ID + | or + | False (boolean) (Transaction create/update failed) |======================================= */ function zeroBS_integrations_addOrUpdateTransaction( - - $transactionExternalSource='', /* Req, e.g. 'str' */ - $transactionExternalID='', /* Req, e.g. 'ch_1DqSxpBy0i6Hd9AL4noH4Yhx' */ - $transactionFields=array(), /* Req: array(orderid,customer,status,total) */ - $transactionTags=array(), /* optional extra tags */ - $transactionDate = '', - $fallbackLog='auto', - $extraMeta = false, + $transactionExternalSource = '', // Required, e.g. 'str'. + $transactionExternalID = '', // Required, e.g. 'ch_1DqSxpBy0i6Hd9AL4noH4Yhx'. + $transactionFields = array(), // Required keys: orderid, customer, status, total. + $transactionTags = array(), + $transactionDate = '', + $fallbackLog = 'auto', + $extraMeta = false, $automatorPassthroughArray = false, $fieldPrefix = 'zbst_' - - ){ +) { #} Check req. if ( - !empty($transactionExternalSource) && !empty($transactionExternalID) && is_array($transactionFields) && count($transactionFields) > 0 && - - ( - // v2 - (isset($transactionFields['orderid']) && !empty($transactionFields['orderid'])) - || - // v3 - (isset($transactionFields['ref']) && !empty($transactionFields['ref'])) - - ) && - //isset($transactionFields['customer']) && !empty($transactionFields['customer']) && - isset($transactionFields['status']) && !empty($transactionFields['status']) && - isset($transactionFields['total']) && !empty($transactionFields['total']) - ){ - - #} Do query for ID - $potentialTransactionID = zeroBS_getTransactionIDWithExternalSource($transactionExternalSource,$transactionExternalID); + ! empty( $transactionExternalSource ) && ! empty( $transactionExternalID ) && is_array( $transactionFields ) && count( $transactionFields ) > 0 && - #} Default fallback log creation - $fallbackLogToPass = false; - if ( - !isset($fallbackLog) || - !is_array($fallbackLog) - ) { + ( + // v2 + ( isset( $transactionFields['orderid'] ) && ! empty( $transactionFields['orderid'] ) ) + || + // v3 + ( isset( $transactionFields['ref'] ) && ! empty( $transactionFields['ref'] ) ) - #} create default fallback log, unless $fallbackLog is set to 'none' - if ($fallbackLog !== 'none'){ + ) && + // isset($transactionFields['customer']) && !empty($transactionFields['customer']) && + isset( $transactionFields['status'] ) && ! empty( $transactionFields['status'] ) && + isset( $transactionFields['total'] ) && ! empty( $transactionFields['total'] ) + ) { - #} Autogen - #} Left this out for v1.1.18... needs thought. - #} Do we really want to put "woo source added"? It might get added loads. - #} For now leave as manual... + #} Do query for ID + $potentialTransactionID = zeroBS_getTransactionIDWithExternalSource( $transactionExternalSource, $transactionExternalID ); - } + #} Default fallback log creation + $fallbackLogToPass = false; + if ( + ! isset( $fallbackLog ) || + ! is_array( $fallbackLog ) + ) { - } elseif (is_array($fallbackLog)){ + #} create default fallback log, unless $fallbackLog is set to 'none' + if ( $fallbackLog !== 'none' ) { - #} Fallback log is probably set, just pass it along. - $fallbackLogToPass = $fallbackLog; + #} Autogen + #} Left this out for v1.1.18... needs thought. + #} Do we really want to put "woo source added"? It might get added loads. + #} For now leave as manual... } + } elseif ( is_array( $fallbackLog ) ) { - #} Here we're passing along any automator pass through - #} ... which will typically be overrides for creation logs or any extra params to give to internal automator. - $automatorPassthrough = false; if (isset($automatorPassthroughArray) && is_array($automatorPassthroughArray)) $automatorPassthrough = $automatorPassthroughArray; + #} Fallback log is probably set, just pass it along. + $fallbackLogToPass = $fallbackLog; - #} Brutal add/update - $transactionWPID = zeroBS_addUpdateTransaction($potentialTransactionID, $transactionFields, $transactionExternalSource, $transactionExternalID, $transactionDate, $transactionTags, $fallbackLogToPass, $extraMeta, $automatorPassthrough,$fieldPrefix); + } + + #} Here we're passing along any automator pass through + #} ... which will typically be overrides for creation logs or any extra params to give to internal automator. + $automatorPassthrough = false; + if ( isset( $automatorPassthroughArray ) && is_array( $automatorPassthroughArray ) ) { + $automatorPassthrough = $automatorPassthroughArray; + } - #} Update any title - #} Not needed for transactions: if ($transactionWPID !== false) zbsCustomer_updateCompanyNameInPostTitle($companyID,false); + #} Brutal add/update + $transactionWPID = zeroBS_addUpdateTransaction( $potentialTransactionID, $transactionFields, $transactionExternalSource, $transactionExternalID, $transactionDate, $transactionTags, $fallbackLogToPass, $extraMeta, $automatorPassthrough, $fieldPrefix ); - return $transactionWPID; + #} Update any title + #} Not needed for transactions: if ($transactionWPID !== false) zbsCustomer_updateCompanyNameInPostTitle($companyID,false); + + return $transactionWPID; } else { // no source/id/fields return false; } - } -// phpcs:ignore Squiz.Commenting.FunctionComment.Missing +/** + * Adds or updates a task via integrations. + * + * @param int $task_id Task ID. + * @param array $data_array Task data. Required keys: 'title', 'to', 'from'. + * @param array $task_reminders Task reminders. Keys: 'remind_at', 'sent' (v3+). + */ function zeroBS_integrations_addOrUpdateTask( - $task_id = -1, /* Req - the task ID */ - $data_array = array(), /* Req: title,to, from */ - $task_reminders = array() /* Req: remind_at,sent (v3+) */ + $task_id = -1, + $data_array = array(), + $task_reminders = array() ) { #} Check req. @@ -879,16 +862,15 @@ function zeroBS_integrations_addOrUpdateTask( ( ! empty( $data_array['start'] ) && ! empty( $data_array['end'] ) ) ) ) { - return zeroBS_addUpdateEvent( $task_id, $data_array, $task_reminders ); + return zeroBS_addUpdateEvent( $task_id, $data_array, $task_reminders ); } else { // no source/id/fields return false; } } - /* |======================================= - | zeroBS_integrations_getTransaction + | zeroBS_integrations_getTransaction |======================================= | Retrieves a transaction record (as usual _getTransaction func) - but one that has been inserted via import from an external source | E.g. Woo Imported, Paypal imported, whatever @@ -899,117 +881,99 @@ function zeroBS_integrations_addOrUpdateTask( | zeroBS_integrations_getTransaction('pay','x3da9j3d9jad2') |======================================= | Returns: - | transaction obj (std class) - | or - | False (boolean) (transaction does not exist) + | transaction obj (std class) + | or + | False (boolean) (transaction does not exist) |======================================= | Check via: if ($transobj !== false) |======================================= */ -function zeroBS_integrations_getTransaction($transactionExternalSource='',$transactionExternalID=''){ +function zeroBS_integrations_getTransaction( $transactionExternalSource = '', $transactionExternalID = '' ) { #} Do query for ID - $potentialTransactionID = zeroBS_getTransactionIDWithExternalSource($transactionExternalSource,$transactionExternalID); + $potentialTransactionID = zeroBS_getTransactionIDWithExternalSource( $transactionExternalSource, $transactionExternalID ); - if ($potentialTransactionID !== false){ + if ( $potentialTransactionID !== false ) { #} If so, pass full deets via this - return zeroBS_getTransaction($potentialTransactionID); + return zeroBS_getTransaction( $potentialTransactionID ); } #} If it gets here, it failed return false; - } - - - - - - - /* For now a wrapper, later will allow us to seemlessly feed in customer generated cats */ -function zeroBS_integrations_getAllCategories($incEmpty=false){ +function zeroBS_integrations_getAllCategories( $incEmpty = false ) { global $zbs; - return array('zerobscrm_customertag' => $zbs->DAL->getTagsForObjType(array( - - 'objtypeid'=>ZBS_TYPE_CONTACT, - 'excludeEmpty'=>!$incEmpty, - 'withCount'=>true, - 'ignoreowner' => true, - // sort - 'sortByField' => 'zbstag_name', - 'sortOrder' => 'ASC' - - ))); - + return array( + 'zerobscrm_customertag' => $zbs->DAL->getTagsForObjType( + array( + + 'objtypeid' => ZBS_TYPE_CONTACT, + 'excludeEmpty' => ! $incEmpty, + 'withCount' => true, + 'ignoreowner' => true, + // sort + 'sortByField' => 'zbstag_name', + 'sortOrder' => 'ASC', + + ) + ), + ); } - #} For now just a wrapper -function zeroBS_integrations_searchCustomers($args=array()){ - - if (!empty($args) && isset($args['searchPhrase'])) return zeroBS_searchCustomers($args); +function zeroBS_integrations_searchCustomers( $args = array() ) { - return array(); + if ( ! empty( $args ) && isset( $args['searchPhrase'] ) ) { + return zeroBS_searchCustomers( $args ); + } + return array(); } -#} Add log (currently a wrapper) +/** + * Adds a log entry (currently a wrapper for zeroBS_addUpdateLog). + * + * @param int $objID Object ID. + * @param int $logDate Log date timestamp. + * @param array $noteFields Note fields array. May include 'meta_assoc_id' + * (e.g. campaign ID for 'email sent' logs) and 'meta_assoc_src' + * (e.g. 'mailcamp'). + * @param string $objType Object type, e.g. 'zerobs_customer' or a ZBS_TYPE_* constant. + */ function zeroBS_integrations_addLog( + $objID = -1, + $logDate = -1, + $noteFields = array(), + $objType = '' +) { - $objID = -1, - /* - is add, doesn't need this: - $logID = -1, - */ - $logDate = -1, - - /* - - NOTE!: as of 31/05/17 WOODY started putting - 'meta_assoc_id' in these - e.g. if it's an 'email sent' log, this meta_assoc_id will be the CAMPAIGN id - 'meta_assoc_src' would then be mailcamp - - */ - - $noteFields = array(), - - /* - DB2 requires obj type, - for now we use zerobs_customer etc. but later we will make these interchangable with TYPES e.g. ZBS_TYPE_CONTACT - */ - - $objType = '' - - ){ - - if (!empty($objID)){ + if ( ! empty( $objID ) ) { #} Add fresh log: - zeroBS_addUpdateLog($objID,-1,$logDate,$noteFields,$objType); + zeroBS_addUpdateLog( $objID, -1, $logDate, $noteFields, $objType ); return true; } return false; - - } // WH added, backward compat: -// only works DAL2 + -function zeroBS_integrations_getCustomFields($objTypeID=-1){ +// only works DAL2 + +function zeroBS_integrations_getCustomFields( $objTypeID = -1 ) { - $objTypeID = (int)$objTypeID; + $objTypeID = (int) $objTypeID; - if ($objTypeID > 0){ + if ( $objTypeID > 0 ) { global $zbs; @@ -1020,6 +984,7 @@ function zeroBS_integrations_getCustomFields($objTypeID=-1){ return array(); } -/* ====================================================== - / Integration specific extension functions - ====================================================== */ +/* +====================================================== + / Integration specific extension functions + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomator.php b/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomator.php index 570dd9289f04..2d6aa68b6548 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomator.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomator.php @@ -1,5 +1,5 @@ -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 +137,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 +155,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..3019696e8582 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomatorRecipes.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.InternalAutomatorRecipes.php @@ -1,5 +1,5 @@ - 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 +792,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 +964,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 +982,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 +1000,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 +1011,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 +1263,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 +1300,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 +1334,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 +1391,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..25d157c64f05 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Inventory.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Inventory.php @@ -1,5 +1,5 @@ - 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 +150,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 +212,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 +295,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 +311,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 +583,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 +788,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 +954,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 +1258,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 +1271,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 +1395,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 +1486,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 +1558,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..3d5a2c5b258a 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.List.Columns.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.List.Columns.php @@ -1,508 +1,510 @@ - 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' ) ), + +); - #{ 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")) - - - ); - - $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 - ===================================================================================================== */ - - - /* ====================================================================================================== - ======================== Invoices - ===================================================================================================== */ - - - global $zeroBSCRM_columns_invoice; - - $zeroBSCRM_columns_invoice = array(); - $zeroBSCRM_columns_invoice['default'] = array( - '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'), - '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'), - '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")), - - // not user-configurable, so disabling for now - //'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), - - ); - - - /* ====================================================================================================== - ======================== / Invoices - ===================================================================================================== */ - - - -/* ====================================================================================================== - ======================== Transactions - ===================================================================================================== */ - - - global $zeroBSCRM_columns_transaction; - - $zeroBSCRM_columns_transaction = array(); - $zeroBSCRM_columns_transaction['default'] = array( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - '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")) - - ); - - $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")) - ); - - $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 - ===================================================================================================== */ +/** + * 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' ) ), + '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' ), + 'customer' => array( __( 'Contact', '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' ) ), + // not user-configurable, so disabling for now + // 'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), +); + +/* +====================================================================================================== + ======================== / Quotes + ===================================================================================================== */ + +/* +====================================================================================================== + ======================== Invoices + ===================================================================================================== */ + +global $zeroBSCRM_columns_invoice; + +$zeroBSCRM_columns_invoice = array(); +$zeroBSCRM_columns_invoice['default'] = array( + 'id' => array( 'ID', false, 'basefield' ), + + 'ref' => array( __( 'Reference', 'zero-bs-crm' ), false, 'basefield' ), + 'customer' => array( __( 'Contact', '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 + 'id' => array( 'ID', false, 'basefield' ), + 'ref' => array( __( 'Reference', 'zero-bs-crm' ), false, 'basefield' ), + 'customer' => array( __( 'Contact', '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' ), + + 'editlink' => array( __( 'Edit', 'zero-bs-crm' ) ), + + // not user-configurable, so disabling for now + // 'assignedobj' => array(__('Assigned To',"zero-bs-crm"),false,'basefield'), +); + +/* +====================================================================================================== + ======================== / Invoices + ===================================================================================================== */ + +/* +====================================================================================================== + ======================== Transactions + ===================================================================================================== */ + +global $zeroBSCRM_columns_transaction; + +$zeroBSCRM_columns_transaction = array(); +$zeroBSCRM_columns_transaction['default'] = array( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + 'id' => array( 'ID', 'zbsDefault_column_customerid', 'basefield' ), + 'customer' => array( __( 'Contact', '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' ), + 'customer' => array( __( 'Contact', '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' ), + + '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' ) ), +); + +$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 /** * Unpacks listview settings */ 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; - - $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( - - '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){ - - // 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; - - if (!$hideCol){ - - $skip = false; // skip addr 2 if off - - // add it - $cfTitle = $fKey; if (is_array($fDetail) && isset($fDetail[1])) $cfTitle = $fDetail[1]; - - // 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); - - - } - - - } - -// phpcs:enable Generic.WhiteSpace.ScopeIndent.Incorrect, Generic.WhiteSpace.ScopeIndent.IncorrectExact + // 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' ); + } + + // 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', + + ); + + 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 ] ) ) { + + // some need hiding (just for api/behind scenes:) + $hideCol = false; + if ( is_array( $fDetail ) && isset( $fDetail['nocolumn'] ) && $fDetail['nocolumn'] ) { + $hideCol = true; + } + + if ( ! $hideCol ) { + + $skip = false; // skip addr 2 if off + + // add it + $cfTitle = $fKey; + if ( is_array( $fDetail ) && isset( $fDetail[1] ) ) { + $cfTitle = $fDetail[1]; + } + + // 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 ); + + } +} diff --git a/projects/plugins/crm/includes/ZeroBSCRM.List.php b/projects/plugins/crm/includes/ZeroBSCRM.List.php index aeaa6e76a851..861199e0970f 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.List.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.List.php @@ -1,5 +1,5 @@ -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 +209,145 @@ public function drawListView(){ $per_page = 20; } - #} Refresh 2 - ?> + #} Refresh 2 + ?> - + - + -
- +
+
@@ -350,7 +373,7 @@ public function drawListView(){
-
+
plural ), sprintf( __( 'There has been a problem retrieving your %s. If this issue persists, please contact support.', 'zero-bs-crm' ), $this->plural ), 'disabled warning sign', 'zbsCantLoadData' ); echo zeroBSCRM_UI2_messageHTML( 'warning hidden', sprintf( __( 'Error updating columns %s', 'zero-bs-crm' ), $this->plural ), __( 'There has been a problem saving your column configuration. If this issue persists, please contact support.', 'zero-bs-crm' ), 'disabled warning sign', 'zbsCantSaveCols' ); echo zeroBSCRM_UI2_messageHTML( 'warning hidden', sprintf( __( 'Error updating columns %s', 'zero-bs-crm' ), $this->plural ), __( 'There has been a problem saving your filter button configuration. If this issue persists, please contact support.', 'zero-bs-crm' ), 'disabled warning sign', 'zbsCantSaveButtons' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - echo zeroBSCRM_UI2_messageHTML( 'info hidden', sprintf( __( 'No %s Found', 'zero-bs-crm' ), $this->plural ), sprintf( __( 'There are no %s here. Do you want to create one?', 'zero-bs-crm' ), $this->plural, jpcrm_esc_link( 'create', -1, $this->postType ) ), 'disabled warning sign', 'zbsNoResults' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + echo zeroBSCRM_UI2_messageHTML( 'info hidden', sprintf( __( 'No %s Found', 'zero-bs-crm' ), $this->plural ), sprintf( __( 'There are no %1$s here. Do you want to create one?', 'zero-bs-crm' ), $this->plural, jpcrm_esc_link( 'create', -1, $this->postType ) ), 'disabled warning sign', 'zbsNoResults' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase // any additional messages? if ( isset( $this->messages ) && is_array( $this->messages ) && count( $this->messages ) > 0 ) { @@ -377,7 +400,7 @@ public function drawListView(){ echo zeroBSCRM_UI2_messageHTML( $message[0], $message[1], $message[2], $message[3], $message[4] ); } } - // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped,WordPress.WP.I18n.MissingTranslatorsComment,WordPress.WP.I18n.UnorderedPlaceholdersText + // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped,WordPress.WP.I18n.MissingTranslatorsComment ?>
@@ -396,190 +419,200 @@ public function drawListView(){ ?> - + esc_html__( 'Could not update', 'zero-bs-crm' ), 'couldntupdatedeets' => esc_html__( 'This record could not be updated. Please try again, if this persists please let admin know.', 'zero-bs-crm' ), /* translators: Placeholders are the range of the current record result and the total object count. */ - 'listview_counts' => esc_html__( 'Showing %s of %s items', 'zero-bs-crm' ), // phpcs:ignore WordPress.WP.I18n.UnorderedPlaceholdersText + 'listview_counts' => esc_html__( 'Showing %1$s of %2$s items', 'zero-bs-crm' ), ); return array_merge( $language_array, $jpcrm_listview_lang_labels ); diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Mail.php b/projects/plugins/crm/includes/ZeroBSCRM.Mail.php index 4ab4a910970f..06bf507e8738 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Mail.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Mail.php @@ -1,54 +1,57 @@ -'; + if ( $withSemanticWrap ) { + echo '
'; + } // none - ?>'; + ?> + '; + } } else { // some - /* Array + /* + Array ( [wordpress-25apr-local] => Array ( @@ -76,134 +79,164 @@ function zeroBSCRM_mailDelivery_accountDDL($selectedOption=-1,$id='zbs-mail-deli // Debug echo '
'; print_r($zbsSMTPAccs); echo '
'; - if ($withSemanticWrap) echo '
'; + if ( $withSemanticWrap ) { + echo '
'; + } - ?> + $acc ) { #} account name etc. $accStr = ''; - if (isset($acc['fromname'])) $accStr = $acc['fromname']; - if (isset($acc['fromemail'])) { - if (!empty($accStr)) - $accStr .= ' <'.$acc['fromemail'].'>'; - else + if ( isset( $acc['fromname'] ) ) { + $accStr = $acc['fromname']; + } + if ( isset( $acc['fromemail'] ) ) { + if ( ! empty( $accStr ) ) { + $accStr .= ' <' . $acc['fromemail'] . '>'; + } else { $accStr .= $acc['fromemail']; } + } #} Mode label (if showing) - if ($showProtocol){ - $accStrExtra = ' (wp_mail)'; - if (isset($acc['mode']) && $acc['mode'] == 'smtp') $accStrExtra = ' (SMTP)'; - $accStr .= $accStrExtra; + if ( $showProtocol ) { + $accStrExtra = ' (wp_mail)'; + if ( isset( $acc['mode'] ) && $acc['mode'] == 'smtp' ) { + $accStrExtra = ' (SMTP)'; } + $accStr .= $accStrExtra; + } #} If default, add that - if ($key == $defaultMailOptionIndex) $accStr .= ' [Default]'; + if ( $key == $defaultMailOptionIndex ) { + $accStr .= ' [Default]'; + } - echo ''; - } ?>'; + } + ?> + + '; + } } - if ($withSemanticWrap){ + if ( $withSemanticWrap ) { - ?> + + ifnot> crmname >ifnot> blog_name -function zeroBSCRM_mailDelivery_defaultFromname(){ - $r = ''; - $business_name = zeroBSCRM_textExpose(zeroBSCRM_getSetting('businessname')); - $r = sanitize_text_field($business_name); +function zeroBSCRM_mailDelivery_defaultFromname() { + $r = ''; + $business_name = zeroBSCRM_textExpose( zeroBSCRM_getSetting( 'businessname' ) ); + $r = sanitize_text_field( $business_name ); // crm name: - if (empty($r)){ - $r = zeroBSCRM_getSetting('customheadertext'); + if ( empty( $r ) ) { + $r = zeroBSCRM_getSetting( 'customheadertext' ); } - - if (empty($r)){ - $blog_name = zeroBSCRM_textExpose(get_bloginfo('name')); - $r = sanitize_text_field($blog_name); + + if ( empty( $r ) ) { + $blog_name = zeroBSCRM_textExpose( get_bloginfo( 'name' ) ); + $r = sanitize_text_field( $blog_name ); } return $r; } -function zeroBSCRM_mailDelivery_defaultEmail(){ +function zeroBSCRM_mailDelivery_defaultEmail() { - /* this can be expaned on later for now it gets the admin email + /* + this can be expaned on later for now it gets the admin email #WH can expand to default email account later */ - return get_bloginfo('admin_email'); + return get_bloginfo( 'admin_email' ); } -/* ====================================================== - / Mail Sending, defaults - ====================================================== */ +/* +====================================================== + / Mail Sending, defaults + ====================================================== */ #} Send a mail via a specific mail delivery profile -// assumes some common-sense in calling, +// assumes some common-sense in calling, // e.g. if you call this with a textbody and no html, but in html mode, it won't fix that for you // NOTE, if $mailDeliveryAccKey == -1, it'll just default to wpmail -function zeroBSCRM_mailDelivery_sendMessage($mailDeliveryAccKey='',$mail=-1){ +function zeroBSCRM_mailDelivery_sendMessage( $mailDeliveryAccKey = '', $mail = -1 ) { global $zbs; - if ($mailDeliveryAccKey !== -1 && !empty($mailDeliveryAccKey) && is_array($mail)){ + if ( $mailDeliveryAccKey !== -1 && ! empty( $mailDeliveryAccKey ) && is_array( $mail ) ) { // using key, send a mail! - $mailSettings = zeroBSCRM_mailDelivery_retrieveACCByKey($mailDeliveryAccKey); + $mailSettings = zeroBSCRM_mailDelivery_retrieveACCByKey( $mailDeliveryAccKey ); - } + } // if passing -1 or failed to load - //... also catches if trying to use a since deleted mail delivery acc - if ($mailDeliveryAccKey == -1 || !is_array($mailSettings)){ + // ... also catches if trying to use a since deleted mail delivery acc + if ( $mailDeliveryAccKey == -1 || ! is_array( $mailSettings ) ) { // see if a default is set $mailSettings = zeroBSCRM_mailDelivery_retrieveDefaultMDAcc(); - //echo 'Mail Setting Default:
'; print_r($mailSettings); echo '
'; - - //... if not default to WP setup: - if (!is_array($mailSettings)) $mailSettings = zeroBSCRM_mailDelivery_retrieveACCWPDefault(); + // echo 'Mail Setting Default:
'; print_r($mailSettings); echo '
'; + // ... if not default to WP setup: + if ( ! is_array( $mailSettings ) ) { + $mailSettings = zeroBSCRM_mailDelivery_retrieveACCWPDefault(); + } } // got settings? - if (isset($mailSettings) && is_array($mailSettings)){ + if ( isset( $mailSettings ) && is_array( $mailSettings ) ) { #} Check settings (roughly) - if (!isset($mailSettings) || !is_array($mailSettings) || !isset($mailSettings['fromemail'])){ + if ( ! isset( $mailSettings ) || ! is_array( $mailSettings ) || ! isset( $mailSettings['fromemail'] ) ) { - return array(false,'errorMsg'=>__('#289Could not load settings for this mail delivery option', 'zero-bs-crm')); + return array( + false, + 'errorMsg' => __( '#289Could not load settings for this mail delivery option', 'zero-bs-crm' ), + ); } #} Check mail (roughly) - if (!isset($mail) || !is_array($mail) || !isset($mail['toEmail'])){ + if ( ! isset( $mail ) || ! is_array( $mail ) || ! isset( $mail['toEmail'] ) ) { - return array(false,'errorMsg'=>__('#290Could not load message for this mail delivery call', 'zero-bs-crm')); + return array( + false, + 'errorMsg' => __( '#290Could not load message for this mail delivery call', 'zero-bs-crm' ), + ); } - /* comes in... + /* + comes in... // build send array $mailArray = array( 'toEmail' => $sendToEmail, @@ -219,7 +252,7 @@ function zeroBSCRM_mailDelivery_sendMessage($mailDeliveryAccKey='',$mail=-1){ ); - EXAMPLE: 10/05/18 wh + EXAMPLE: 10/05/18 wh $mailDeliveryIndxKey = -1; @@ -255,160 +288,192 @@ function zeroBSCRM_mailDelivery_sendMessage($mailDeliveryAccKey='',$mail=-1){ // seems legit. Build email components $sendToEmail = ''; - $subject = ''; - $headers = array(); - $body = ''; - $textBody = ''; - $options = array( - 'html' => 1 + $subject = ''; + $headers = array(); + $body = ''; + $textBody = ''; + $options = array( + 'html' => 1, ); - + // send to - if (isset($mail['toEmail']) && !empty($mail['toEmail']) && zeroBSCRM_validateEmail($mail['toEmail'])) $sendToEmail = $mail['toEmail']; - + if ( isset( $mail['toEmail'] ) && ! empty( $mail['toEmail'] ) && zeroBSCRM_validateEmail( $mail['toEmail'] ) ) { + $sendToEmail = $mail['toEmail']; + } + // subject can be empty - if (isset($mail['subject'])) $subject = $mail['subject']; + if ( isset( $mail['subject'] ) ) { + $subject = $mail['subject']; + } // body can't be... - if (isset($mail['body']) && !empty($mail['body'])) $body = $mail['body']; - if (isset($mail['textbody']) && !empty($mail['textbody'])) $textBody = $mail['textbody']; + if ( isset( $mail['body'] ) && ! empty( $mail['body'] ) ) { + $body = $mail['body']; + } + if ( isset( $mail['textbody'] ) && ! empty( $mail['textbody'] ) ) { + $textBody = $mail['textbody']; + } // options - if (isset($mail['options']) && is_array($mail['options'])){ - - // html? - rough - if (isset($mail['options']['html']) && $mail['options']['html'] == "1") - $options['html'] = 1; - if (isset($mail['options']['html']) && $mail['options']['html'] == "-1") - $options['html'] = -1; + if ( isset( $mail['options'] ) && is_array( $mail['options'] ) ) { + // html? - rough + if ( isset( $mail['options']['html'] ) && $mail['options']['html'] == '1' ) { + $options['html'] = 1; } + if ( isset( $mail['options']['html'] ) && $mail['options']['html'] == '-1' ) { + $options['html'] = -1; + } + } // attachments $attachments = array(); - if (isset($mail['attachments']) && is_array($mail['attachments'])){ + if ( isset( $mail['attachments'] ) && is_array( $mail['attachments'] ) ) { - // check through em + check file_exists, otherwise pass on - if (count($mail['attachments']) > 0) foreach ($mail['attachments'] as $file){ + // check through em + check file_exists, otherwise pass on + if ( count( $mail['attachments'] ) > 0 ) { + foreach ( $mail['attachments'] as $file ) { // here we switch as sometimes meaningful names given via array - if (is_array($file)){ - - if (file_exists($file[0])) $attachments[] = $file; + if ( is_array( $file ) ) { - } else { - - if (file_exists($file)) $attachments[] = $file; + if ( file_exists( $file[0] ) ) { + $attachments[] = $file; + } + } elseif ( file_exists( $file ) ) { + $attachments[] = $file; } - } - - } + } // headers - if (isset($mail['headers']) && is_array($mail['headers'])){ + if ( isset( $mail['headers'] ) && is_array( $mail['headers'] ) ) { - // just copy em for now - $headers = $mail['headers']; + // just copy em for now + $headers = $mail['headers']; - } + } // check headers & options (e.g. inject html...) // html mode - if ($options['html'] == 1){ + if ( $options['html'] == 1 ) { - $headerPresent = false; - foreach ($headers as $h){ - if ($h == 'Content-Type: text/html; charset=UTF-8') { $headerPresent = true; break; } - } - if (!$headerPresent) $headers[] = 'Content-Type: text/html; charset=UTF-8'; - - } + $headerPresent = false; + foreach ( $headers as $h ) { + if ( $h == 'Content-Type: text/html; charset=UTF-8' ) { + $headerPresent = true; + break; } + } + if ( ! $headerPresent ) { + $headers[] = 'Content-Type: text/html; charset=UTF-8'; + } + } // catch any overrides and put in place (currently only send name) - if (isset($mail['overrideSendName']) && !empty($mail['overrideSendName'])) $mailSettings['fromname'] = $mail['overrideSendName']; + if ( isset( $mail['overrideSendName'] ) && ! empty( $mail['overrideSendName'] ) ) { + $mailSettings['fromname'] = $mail['overrideSendName']; + } // do final checks & send per mode #} Check mail (roughly) - if (empty($body) || empty($sendToEmail) || !zeroBSCRM_validateEmail($sendToEmail)) { + if ( empty( $body ) || empty( $sendToEmail ) || ! zeroBSCRM_validateEmail( $sendToEmail ) ) { - return array(false,'errorMsg'=>__('#291Could not process message details for this mail delivery call', 'zero-bs-crm')); + return array( + false, + 'errorMsg' => __( '#291Could not process message details for this mail delivery call', 'zero-bs-crm' ), + ); - } + } // Tracking Pixels? // first we check whether it's been globally turned off.. - $trackingEnabled = $zbs->settings->get('emailtracking'); + $trackingEnabled = $zbs->settings->get( 'emailtracking' ); // proceed - if (isset($mail['tracking']) && is_array($mail['tracking']) && count($mail['tracking']) > 0){ + if ( isset( $mail['tracking'] ) && is_array( $mail['tracking'] ) && count( $mail['tracking'] ) > 0 ) { - // work out the tracking params - $emailTypeID = -1; if (isset($mail['tracking']['emailTypeID'])) $emailTypeID = $mail['tracking']['emailTypeID']; - $targetObjID = -1; if (isset($mail['tracking']['targetObjID'])) $targetObjID = $mail['tracking']['targetObjID']; - $senderWPID = 0; if (isset($mail['tracking']['senderWPID'])) $senderWPID = $mail['tracking']['senderWPID']; - $senderEmailAddress = $mailSettings['fromemail']; - $associatedObjID = -1; if (isset($mail['tracking']['associatedObjID'])) $associatedObjID = $mail['tracking']['associatedObjID']; - $emailSubject = ''; if (isset($mail['subject'])) $emailSubject = $mail['subject']; + // work out the tracking params + $emailTypeID = -1; + if ( isset( $mail['tracking']['emailTypeID'] ) ) { + $emailTypeID = $mail['tracking']['emailTypeID']; + } + $targetObjID = -1; + if ( isset( $mail['tracking']['targetObjID'] ) ) { + $targetObjID = $mail['tracking']['targetObjID']; + } + $senderWPID = 0; + if ( isset( $mail['tracking']['senderWPID'] ) ) { + $senderWPID = $mail['tracking']['senderWPID']; + } + $senderEmailAddress = $mailSettings['fromemail']; + $associatedObjID = -1; + if ( isset( $mail['tracking']['associatedObjID'] ) ) { + $associatedObjID = $mail['tracking']['associatedObjID']; + } + $emailSubject = ''; + if ( isset( $mail['subject'] ) ) { + $emailSubject = $mail['subject']; + } - $thread = -1; if (isset($mail['thread'])) $thread = $mail['thread']; + $thread = -1; + if ( isset( $mail['thread'] ) ) { + $thread = $mail['thread']; + } - //v2.94.1 storing email content in the table - $emailContent = ''; if (isset($mail['content'])) { + // v2.94.1 storing email content in the table + $emailContent = ''; if ( isset( $mail['content'] ) ) { - // NOTE: we can apply wpeditor here because the only part of zbs using this 'content' addition is mikes emails - //... but this does FORCE us to be using same wp_editor format unless we do a migration - //... for now living with that [WH 18/10/18] - $emailContent = wp_kses( $mail['content'], $zbs->acceptable_html ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // NOTE: we can apply wpeditor here because the only part of zbs using this 'content' addition is mikes emails + // ... but this does FORCE us to be using same wp_editor format unless we do a migration + // ... for now living with that [WH 18/10/18] + $emailContent = wp_kses( $mail['content'], $zbs->acceptable_html ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - } + } - // log the email (presend) + generate hash - $trackingHash = zeroBSCRM_mailTracking_logEmail($emailTypeID,$targetObjID,$senderWPID,$senderEmailAddress,$associatedObjID,$emailSubject,true, $emailContent, $thread, $sendToEmail, 'sent', $mailDeliveryAccKey); + // log the email (presend) + generate hash + $trackingHash = zeroBSCRM_mailTracking_logEmail( $emailTypeID, $targetObjID, $senderWPID, $senderEmailAddress, $associatedObjID, $emailSubject, true, $emailContent, $thread, $sendToEmail, 'sent', $mailDeliveryAccKey ); - if ($trackingEnabled == "1"){ - - // inject the hash img (only if using tracking) - $body = zeroBSCRM_mailTracking_addPixel($body,$trackingHash); + if ( $trackingEnabled == '1' ) { - } + // inject the hash img (only if using tracking) + $body = zeroBSCRM_mailTracking_addPixel( $body, $trackingHash ); } + } // the subject sometimes comes with html entities because the way some placeholders are stored in the db (e.g. ##BIZ-NAME##). See PR #1640 - $decoded_subject = zeroBSCRM_textExpose($subject); + $decoded_subject = zeroBSCRM_textExpose( $subject ); // mode-checks & send - switch ($mailSettings['mode']){ - + switch ( $mailSettings['mode'] ) { case 'wp_mail': - // WP mail needs to check from is in header (if someone's added, override :)) // From (esp req for wpmail): - $newHeaders = array(); + $newHeaders = array(); $headerPresent = false; foreach ( $headers as $h ) { if ( str_starts_with( $h, 'From:' ) ) { // replace it :) - $newHeaders[] = 'From: '.$mailSettings['fromname'].' <'.$mailSettings['fromemail'].'>'; + $newHeaders[] = 'From: ' . $mailSettings['fromname'] . ' <' . $mailSettings['fromemail'] . '>'; } else { // just add to new arr $newHeaders[] = $h; } - } // if no from, we need to add it! - if (!$headerPresent) $newHeaders[] = 'From: '.$mailSettings['fromname'].' <'.$mailSettings['fromemail'].'>'; + if ( ! $headerPresent ) { + $newHeaders[] = 'From: ' . $mailSettings['fromname'] . ' <' . $mailSettings['fromemail'] . '>'; + } // and overwrite it... (if nothing changed, doesn't matter :)) $headers = $newHeaders; @@ -416,58 +481,57 @@ function zeroBSCRM_mailDelivery_sendMessage($mailDeliveryAccKey='',$mail=-1){ // Here we check $attachments, because these can optionally be passed as arrays with 'meaningful names' as second var // .. but no easy way to get wp_mail to use meaningful names // so just remove - if (is_array($attachments) && count($attachments) > 0){ - $a = array(); - foreach ($attachments as $attachment){ - if (is_array($attachment)){ + if ( is_array( $attachments ) && count( $attachments ) > 0 ) { + $a = array(); + foreach ( $attachments as $attachment ) { + if ( is_array( $attachment ) ) { - // probs passed, just dump first val for now - $a[] = $attachment[0]; + // probs passed, just dump first val for now + $a[] = $attachment[0]; - } else $a[] = $attachment; + } else { + $a[] = $attachment; } - $attachments = $a; } + $attachments = $a; + } // sends to itself to test $sent = wp_mail( $sendToEmail, $decoded_subject, $body, $headers, $attachments ); - break; - + break; case 'smtp': - #} go $sent = zeroBSCRM_mailDelivery_sendViaSMTP( - #} SMTP Settings - $mailSettings['host'], - $mailSettings['port'], - $mailSettings['user'], - zeroBSCRM_mailDelivery_retKeyData($mailSettings['pass']), - #'tls', #tls ssl - switched for option: + $mailSettings['host'], + $mailSettings['port'], + $mailSettings['user'], + zeroBSCRM_mailDelivery_retKeyData( $mailSettings['pass'] ), + #'tls', #tls ssl - switched for option: $mailSettings['sec'], - #} FROM + #} FROM $mailSettings['fromemail'], - $mailSettings['fromname'], - #} To - $sendToEmail,'', - #} Deets + $mailSettings['fromname'], + #} To + $sendToEmail, + '', + #} Deets $decoded_subject, - $textBody, - $body, - #} Following would return debug - false, + $textBody, + $body, + #} Following would return debug false, - #} Attachments + false, + #} Attachments $attachments ); - break; + break; // API (OAuth) as at 5.1, only google_mail case 'api': - $zbs->load_oauth_handler(); $sent = jpcrm_mail_delivery_send_via_gmail_oauth( @@ -494,102 +558,115 @@ function zeroBSCRM_mailDelivery_sendMessage($mailDeliveryAccKey='',$mail=-1){ break; default: - - return array(false,'errorMsg'=>__('#289Mail Delivery mode not found', 'zero-bs-crm')); + return array( + false, + 'errorMsg' => __( '#289Mail Delivery mode not found', 'zero-bs-crm' ), + ); break; } - // at this point $sent will be success bool :) // log?!? (leave to calling funcs.) // ... well if using tracking pixels, log that: // we still LOG here even if $trackingEnabled !== "1" ... because this just logs 'sent' not any pixelage - if ($sent && isset($trackingHash)) { + if ( $sent && isset( $trackingHash ) ) { // log fact it sent - zeroBSCRM_mailTracking_logSend($trackingHash); + zeroBSCRM_mailTracking_logSend( $trackingHash ); } - // for now, just return - return array($sent); + return array( $sent ); - } - - return array(false,'errorMsg'=>__('#297No settings found for this mail delivery option', 'zero-bs-crm')); + } + return array( + false, + 'errorMsg' => __( '#297No settings found for this mail delivery option', 'zero-bs-crm' ), + ); } // [DREAMWORLD]: WH $arg'itizes this -function zeroBSCRM_mailDelivery_sendViaSMTP($smtpHost='',$smtpPort='',$smtpUser='',$smtpPass='',$smtpSecurity='tls',$sendFrom='',$sendFromName='',$toEmail='',$toName='',$subject='',$msgText='',$msgHTML='',$debugMail=false,$returnDebug=false,$attachments=false){ #,$ccEmails='',$bccEmails='',$replyToAddr='',$returnPath='' +function zeroBSCRM_mailDelivery_sendViaSMTP( $smtpHost = '', $smtpPort = '', $smtpUser = '', $smtpPass = '', $smtpSecurity = 'tls', $sendFrom = '', $sendFromName = '', $toEmail = '', $toName = '', $subject = '', $msgText = '', $msgHTML = '', $debugMail = false, $returnDebug = false, $attachments = false ) { + #,$ccEmails='',$bccEmails='',$replyToAddr='',$returnPath='' global $retDebugStr; - if ($debugMail) $retDebugStr = '

Debugging SMTP

'; + if ( $debugMail ) { + $retDebugStr = '

Debugging SMTP

'; + } #} was going to fallback to default "sendFrom", but these should not be fired without! - for now use brand name :) - if (empty($sendFromName)) $sendFromName = 'Jetpack CRM'; + if ( empty( $sendFromName ) ) { + $sendFromName = 'Jetpack CRM'; + } if ( - !empty($smtpHost) && - !empty($smtpUser) && - !empty($smtpPass) && - !empty($smtpPort) - ){ + ! empty( $smtpHost ) && + ! empty( $smtpUser ) && + ! empty( $smtpPass ) && + ! empty( $smtpPort ) + ) { - global $zbsDebug; $zbsDebug['return'] = $returnDebug; $zbsDebug['debug'] = $debugMail; + global $zbsDebug; + $zbsDebug['return'] = $returnDebug; + $zbsDebug['debug'] = $debugMail; // here we set err handler to avoid any leaked php warnings knocking over the ui // https://stackoverflow.com/questions/1241728/can-i-try-catch-a-warning // $errno represents: https://www.tutorialrepublic.com/php-reference/php-error-levels.php - set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) { + set_error_handler( + function ( $errno, $errstr, $errfile, $errline, array $errcontext ) { - /* */global $retDebugStr,$zbsDebug; - - if ($zbsDebug['debug']){ + global $retDebugStr,$zbsDebug; - if ($zbsDebug['return']) - $retDebugStr .= '===
PHP Level Warning '.$errno.': '.$errstr.' (L:'.$errline.' in '.$errfile.')
'; - else - echo 'PHP Level Warning '. esc_html( $errno.': '.$errstr ) .' (L:'. esc_html( $errline.' in '.$errfile ).')
'; + if ( $zbsDebug['debug'] ) { + if ( $zbsDebug['return'] ) { + $retDebugStr .= '===
PHP Level Warning ' . $errno . ': ' . $errstr . ' (L:' . $errline . ' in ' . $errfile . ')
'; + } else { + echo 'PHP Level Warning ' . esc_html( $errno . ': ' . $errstr ) . ' (L:' . esc_html( $errline . ' in ' . $errfile ) . ')
'; + } } // make it more serious than a warning so it can be caught - //trigger_error($errstr, E_ERROR); - //return true; + // trigger_error($errstr, E_ERROR); + // return true; global $retDebugStr,$zbsDebug; - //return array('details'=>true,'sent'=>false,'stage'=>-1,'debugs'=>array($retDebugStr)); + // return array('details'=>true,'sent'=>false,'stage'=>-1,'debugs'=>array($retDebugStr)); /* Don't execute PHP internal error handler */ return true; - }); + } + ); - if ($debugMail) $retDebugStr .= 'SMTP Details Present
'; + if ( $debugMail ) { + $retDebugStr .= 'SMTP Details Present
'; + } // Rather than use PHPMailer direct, we use the built into wp ver loadMailer(); - //https://developer.wordpress.org/reference/functions/wp_mail/ + // https://developer.wordpress.org/reference/functions/wp_mail/ // =============== CODE FROM wp_mail global $phpmailer; - + // (Re)create it, if it's gone missing if ( ! ( $phpmailer instanceof PHPMailer ) ) { - // WP 5.5 updates PHP Mailer: + // WP 5.5 updates PHP Mailer: // https://make.wordpress.org/core/2020/07/01/external-library-updates-in-wordpress-5-5-call-for-testing/ - if (jpcrm_wordpress_version('>=','5.5')){ + if ( jpcrm_wordpress_version( '>=', '5.5' ) ) { require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php'; require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php'; require_once ABSPATH . WPINC . '/PHPMailer/Exception.php'; $phpmailer = new PHPMailer\PHPMailer\PHPMailer(); - + } else { - + // pre 5.5: require_once ABSPATH . WPINC . '/class-phpmailer.php'; require_once ABSPATH . WPINC . '/class-smtp.php'; @@ -606,18 +683,19 @@ class_alias( phpmailerException::class, 'PHPMailerException' ); $phpmailer->clearReplyTos(); // =============== / CODE FROM wp_mail - #https://webolio.wordpress.com/2008/03/02/phpmailer-and-smtp-on-1and1-shared-hosting/ #} SMTP outbound is killed on 1and1, basically. Has to be on AWS - + #} SMTP Settings // changed $mail to $phpmailer: $mail = new PHPMailer(); - if ($debugMail) { - if (!$returnDebug) echo '
'; #} This is for the mail func debugger
+		if ( $debugMail ) {
+			if ( ! $returnDebug ) {
+				echo '
'; #} This is for the mail func debugger
+			}
 			$retDebugStr .= 'Mailer loaded
'; #} This'll be output AFTER debugger natural echoes } - + /* MY ORIGINAL SETTINGS: */ $phpmailer->IsSMTP(); #THIS MEANS IT IGNORES SMTP!!!!: @@ -626,47 +704,46 @@ class_alias( phpmailerException::class, 'PHPMailerException' ); $phpmailer->SMTPSecure = $smtpSecurity; // Optionally allow OVERRIDE of this setting (checks ssl certs match) - $ignoreSSLMismatch = zeroBSCRM_getSetting('mailignoresslmismatch'); - if ($ignoreSSLMismatch == "1"){ + $ignoreSSLMismatch = zeroBSCRM_getSetting( 'mailignoresslmismatch' ); + if ( $ignoreSSLMismatch == '1' ) { // https://stackoverflow.com/questions/30371910/phpmailer-generates-php-warning-stream-socket-enable-crypto-peer-certificate $phpmailer->SMTPOptions = array( 'ssl' => array( - 'verify_peer' => false, - 'verify_peer_name' => false, - 'allow_self_signed' => true - ) + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true, + ), ); } - + #} Modified this to overcome peoples faulty certificates # http://stackoverflow.com/questions/30371910/phpmailer-generates-php-warning-stream-socket-enable-crypto-peer-certificate #if ($smtpSecurity == 'tls'){ # just times out! #$phpmailer->Host = gethostbyname('tls://'.$smtpHost); - + #} else { - - $phpmailer->Host = $smtpHost; - + + $phpmailer->Host = $smtpHost; + #} - - - $phpmailer->Username = $smtpUser; - $phpmailer->Password = $smtpPass; + + $phpmailer->Username = $smtpUser; + $phpmailer->Password = $smtpPass; #} Added from http://www.9lessons.info/2012/02/amazon-simple-email-service-smtp-using.html #$phpmailer->Mailer = "smtp"; $phpmailer->Port = $smtpPort; #587; // SMTP Port - 465 = SSL, 587 = TLS (USE SSL!) #gmail - $phpmailer->IsHTML(true); + $phpmailer->IsHTML( true ); #$phpmailer->SMTPDebug = 1; // debugging: 1 = errors and messages, 2 = messages only - - /* GMAIL EXAMPLE -http://stackoverflow.com/questions/13574166/phpmailer-send-gmail-smtp-timeout */ + /* + GMAIL EXAMPLE -http://stackoverflow.com/questions/13574166/phpmailer-send-gmail-smtp-timeout */ #$phpmailer->IsSMTP(); // Use SMTP #$phpmailer->Host = "smtp.gmail.com"; // Sets SMTP server #$phpmailer->SMTPDebug = 2; // 2 to enable SMTP debug information @@ -675,247 +752,267 @@ class_alias( phpmailerException::class, 'PHPMailerException' ); #$phpmailer->Port = 587; // set the SMTP port #$phpmailer->Username = 'MyGmail@gmail.com'; // SMTP account username #$phpmailer->Password = 'MyGmailPassword'; // SMTP account password - //$phpmailer->Priority = 1; // Highest priority - Email priority (1 = High, 3 = Normal, 5 = low) - $phpmailer->CharSet = 'UTF-8'; - $phpmailer->Encoding = '8bit'; + // $phpmailer->Priority = 1; // Highest priority - Email priority (1 = High, 3 = Normal, 5 = low) + $phpmailer->CharSet = 'UTF-8'; + $phpmailer->Encoding = '8bit'; #$phpmailer->Subject = 'Test Email Using Gmail'; $phpmailer->ContentType = 'text/html; charset=utf-8'; // see my answer here https://stackoverflow.com/questions/15880042/phpmailer-the-following-smtp-error-data-not-accepted/54887925#54887925 #$phpmailer->From = 'MyGmail@gmail.com'; #$phpmailer->FromName = 'GMail Test'; - $phpmailer->WordWrap = 900; // RFC 2822 Compliant for Max 998 characters per line + $phpmailer->WordWrap = 900; // RFC 2822 Compliant for Max 998 characters per line + + if ( $debugMail ) { + $retDebugStr .= 'Mailer settings overriden
'; + } - - if ($debugMail) $retDebugStr .= 'Mailer settings overriden
'; - #} http://stackoverflow.com/questions/2896280/debugging-php-mail-and-or-phpmailer #} Updated to 5.2.16 # https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting - if ($debugMail) $phpmailer->SMTPDebug = 2; + if ( $debugMail ) { + $phpmailer->SMTPDebug = 2; + } #https://github.com/PHPMailer/PHPMailer/blob/master/docs/Note_for_SMTP_debugging.md - if ($returnDebug) $phpmailer->Debugoutput = function($str, $level) { - # brutal - global $retDebugStr; - #echo "debug level $level; message: $str"; - $retDebugStr .= $level.': message: '.$str." - "; - - }; + if ( $returnDebug ) { + $phpmailer->Debugoutput = function ( $str, $level ) { + # brutal + global $retDebugStr; + #echo "debug level $level; message: $str"; + $retDebugStr .= $level . ': message: ' . $str . ' + '; + }; + } #} Set From & Subject - $phpmailer->SetFrom($sendFrom, $sendFromName,false); //from (verified email address) - $phpmailer->Subject = $subject; //subject + $phpmailer->SetFrom( $sendFrom, $sendFromName, false ); // from (verified email address) + $phpmailer->Subject = $subject; // subject #} Actual Message - //NOTE: This func forces a text ver from the html (not useful if using altbody below): + // NOTE: This func forces a text ver from the html (not useful if using altbody below): // $phpmailer->MsgHTML($msgHTML); // ... ->Body seems to be the correct opt $phpmailer->Body = $msgHTML; // or is it ? https://stackoverflow.com/questions/15880042/phpmailer-the-following-smtp-error-data-not-accepted // add fallback txt if set: https://stackoverflow.com/questions/22507176/send-html-and-plain-text-email-simultaneously-with-php-mailer - if (isset($msgText) && !empty($msgText)) $phpmailer->AltBody = $msgText; + if ( isset( $msgText ) && ! empty( $msgText ) ) { + $phpmailer->AltBody = $msgText; + } #} Recipient(s) #} Currently stored as csv in defined ^^ so discern.... messy, improve. if ( str_contains( $toEmail, ',' ) && str_contains( $toName, ',' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $toEmail = explode(',',$toEmail); - $toName = explode(',',$toName); + $toEmail = explode( ',', $toEmail ); + $toName = explode( ',', $toName ); } #} Legit? - if (is_array($toEmail) && is_array($toName)){ + if ( is_array( $toEmail ) && is_array( $toName ) ) { #} Multiple - this could be much smarter. re-adjust later - $ind = 0; foreach ($toEmail as $em){ - $phpmailer->AddAddress($em, $toName[$ind]); - $ind++; + $ind = 0; foreach ( $toEmail as $em ) { + $phpmailer->AddAddress( $em, $toName[ $ind ] ); + ++$ind; } + } else { #} Singular + $phpmailer->AddAddress( $toEmail, $toName ); + } - } else #} Singular - $phpmailer->AddAddress($toEmail, $toName); - - if ($debugMail) $retDebugStr .= 'Mail body prepped
'; - + if ( $debugMail ) { + $retDebugStr .= 'Mail body prepped
'; + } - #} Attachments + #} Attachments // half-inched from https://core.trac.wordpress.org/browser/tags/4.9/src/wp-includes/pluggable.php#L460 // then modified to allow diff names // https://stackoverflow.com/questions/16776073/phpmailer-sent-attachment-as-other-name - if ( !empty( $attachments ) ) { - foreach ( $attachments as $attachment ) { - try { - if (is_array($attachment)){ + if ( ! empty( $attachments ) ) { + foreach ( $attachments as $attachment ) { + try { + if ( is_array( $attachment ) ) { - if (count($attachment) == 2 ){ + if ( count( $attachment ) == 2 ) { - // pass 2 vars, second will be desired end name - $phpmailer->addAttachment($attachment[0],$attachment[1]); + // pass 2 vars, second will be desired end name + $phpmailer->addAttachment( $attachment[0], $attachment[1] ); - } else { - - // normal, using firs var.. - $phpmailer->addAttachment($attachment[0]); - } + } else { - } else { - $phpmailer->addAttachment($attachment); - } - } catch ( PHPMailerException $e ) { - continue; + // normal, using firs var.. + $phpmailer->addAttachment( $attachment[0] ); } + } else { + $phpmailer->addAttachment( $attachment ); + } + } catch ( PHPMailerException $e ) { + continue; } + } } - // Set to use PHP's mail() // WH Note: Copied this from wp_mail, I wasn't using it in prospectrr setup, does this mean might be SERVER specific to 1and1 // ... follow wp's lead here. - //THIS WAS A CULPRIT (2.94.2 fix) + // THIS WAS A CULPRIT (2.94.2 fix) // THIS should only be on for wp_mail stuff // $phpmailer->isMail(); - //debug echo '
'; print_r(array($smtpHost,$smtpPort,$smtpUser,$smtpPass,$smtpSecurity,$sendFrom,$sendFromName,$toEmail,$toName,$subject,$msgText,$msgHTML,$debugMail,$returnDebug));echo '
'; + // debug echo '
'; print_r(array($smtpHost,$smtpPort,$smtpUser,$smtpPass,$smtpSecurity,$sendFrom,$sendFromName,$toEmail,$toName,$subject,$msgText,$msgHTML,$debugMail,$returnDebug));echo '
'; try { // test: // https://stackoverflow.com/questions/15880042/phpmailer-the-following-smtp-error-data-not-accepted - //$phpmailer->SMTPDebug = 2; + // $phpmailer->SMTPDebug = 2; #} Success? - if ($phpmailer->Send()) { - - if ($debugMail) { - $retDebugStr .= '
Mail sent successfully
'; - if (!$returnDebug) - echo $retDebugStr; - else - return 'success:'.$retDebugStr; + if ( $phpmailer->Send() ) { + + if ( $debugMail ) { + $retDebugStr .= '
Mail sent successfully
'; + if ( ! $returnDebug ) { + echo $retDebugStr; + } else { + return 'success:' . $retDebugStr; } - return true;#DEBUG array(true,$phpmailer->Host,$phpmailer->Username,$phpmailer->Password); #true; + } + return true;#DEBUG array(true,$phpmailer->Host,$phpmailer->Username,$phpmailer->Password); #true; - } else { + } else { - #} Brutal - #NO, frontend! - #DEBUG - #print_r(array(true,$phpmailer->Host,$phpmailer->Username,$phpmailer->Password,$phpmailer->Port)); - #exit("Mailer Error: " . $phpmailer->ErrorInfo); - if ($debugMail) { - $retDebugStr .= '
Mail FAILED #exit-1
'; - if (!$returnDebug) { - echo '
'.$retDebugStr; - echo "Mailer Error: " . $phpmailer->ErrorInfo; - echo '
'; - } else { - return $retDebugStr.'===
Final Error
error:'.$phpmailer->ErrorInfo; - } + #} Brutal + #NO, frontend! + #DEBUG + #print_r(array(true,$phpmailer->Host,$phpmailer->Username,$phpmailer->Password,$phpmailer->Port)); + #exit("Mailer Error: " . $phpmailer->ErrorInfo); + if ( $debugMail ) { + $retDebugStr .= '
Mail FAILED #exit-1
'; + if ( ! $returnDebug ) { + echo '
' . $retDebugStr; + echo 'Mailer Error: ' . $phpmailer->ErrorInfo; + echo '
'; + } else { + return $retDebugStr . '===
Final Error
error:' . $phpmailer->ErrorInfo; } - return false; } + return false; + } + } catch ( PHPMailerException $e ) { - } catch ( PHPMailerException $e ) { - - if ($debugMail) { - - $mail_error_data = array( 'to', 'subject', 'message', 'headers', 'attachments' ); - if (isset($toEmail)) $mail_error_data['to'] = $toEmail; - if (isset($subject)) $mail_error_data['subject'] = $subject; - // likely huge & not necessary below: - //if (isset($message)) $mail_error_data['message'] = $message; - if (isset($attachments)) $mail_error_data['attachments'] = $attachments; - $mail_error_data['phpmailer_exception_code'] = esc_html($e->getCode()); - $mail_error_data['phpmailer_exception_msg'] = esc_html($e->getMessage()); - - // append to the - - if (!$returnDebug) { - echo ''.$retDebugStr; - echo "Mailer Error: " . $phpmailer->ErrorInfo; - echo "Mailer Error2: " . $e->getMessage(); - echo '
'; print_r($mail_error_data); echo '
'; - echo '
'; - } else { - return $retDebugStr.'---
'.print_r($mail_error_data,1).'
---
===
Final Error
error:'.$phpmailer->ErrorInfo; - } - } - return false; - - } catch (Exception $e){ - - // general exception - - if ($debugMail) { - - $mail_error_data = array( 'to', 'subject', 'message', 'headers', 'attachments' ); - if (isset($toEmail)) $mail_error_data['to'] = $toEmail; - if (isset($subject)) $mail_error_data['subject'] = $subject; - // likely huge & not necessary below: - //if (isset($message)) $mail_error_data['message'] = $message; - if (isset($attachments)) $mail_error_data['attachments'] = $attachments; - $mail_error_data['phpmailer_exception_code'] = $e->getCode(); - $mail_error_data['phpmailer_exception_errinfo'] = $phpmailer->ErrorInfo; - - $retDebugStr .= '
Mail FAILED #exit-3
'; - if (!$returnDebug) { - echo ''.$retDebugStr; - echo "Mailer Error: " . $phpmailer->ErrorInfo; - echo "Mailer Error2: " . $e->getMessage(); - echo '
'; print_r($mail_error_data); echo '
'; - echo '
'; - } else { - return $retDebugStr.'---
'.print_r($mail_error_data,1).'
---
===
Final Error
error:'.$e->getMessage(); - } - } - return false; - } finally { + if ( $debugMail ) { + + $mail_error_data = array( 'to', 'subject', 'message', 'headers', 'attachments' ); + if ( isset( $toEmail ) ) { + $mail_error_data['to'] = $toEmail; + } + if ( isset( $subject ) ) { + $mail_error_data['subject'] = $subject; + } + // likely huge & not necessary below: + // if (isset($message)) $mail_error_data['message'] = $message; + if ( isset( $attachments ) ) { + $mail_error_data['attachments'] = $attachments; + } + $mail_error_data['phpmailer_exception_code'] = esc_html( $e->getCode() ); + $mail_error_data['phpmailer_exception_msg'] = esc_html( $e->getMessage() ); + + // append to the + + if ( ! $returnDebug ) { + echo '' . $retDebugStr; + echo 'Mailer Error: ' . $phpmailer->ErrorInfo; + echo 'Mailer Error2: ' . $e->getMessage(); + echo '
';
+					print_r( $mail_error_data );
+					echo '
'; + echo '
'; + } else { + return $retDebugStr . '---
' . print_r( $mail_error_data, 1 ) . '
---
===
Final Error
error:' . $phpmailer->ErrorInfo; + } + } + return false; + + } catch ( Exception $e ) { + + // general exception + + if ( $debugMail ) { - restore_error_handler(); + $mail_error_data = array( 'to', 'subject', 'message', 'headers', 'attachments' ); + if ( isset( $toEmail ) ) { + $mail_error_data['to'] = $toEmail; + } + if ( isset( $subject ) ) { + $mail_error_data['subject'] = $subject; + } + // likely huge & not necessary below: + // if (isset($message)) $mail_error_data['message'] = $message; + if ( isset( $attachments ) ) { + $mail_error_data['attachments'] = $attachments; + } + $mail_error_data['phpmailer_exception_code'] = $e->getCode(); + $mail_error_data['phpmailer_exception_errinfo'] = $phpmailer->ErrorInfo; + + $retDebugStr .= '
Mail FAILED #exit-3
'; + if ( ! $returnDebug ) { + echo '' . $retDebugStr; + echo 'Mailer Error: ' . $phpmailer->ErrorInfo; + echo 'Mailer Error2: ' . $e->getMessage(); + echo '
';
+					print_r( $mail_error_data );
+					echo '
'; + echo '
'; + } else { + return $retDebugStr . '---
' . print_r( $mail_error_data, 1 ) . '
---
===
Final Error
error:' . $e->getMessage(); + } } + return false; + } finally { + restore_error_handler(); + } } return false; - } #} check SMTP Deets -function zeroBSCRM_mailDelivery_checkSMTPDetails($sendFromName='',$sendFromEmail='',$smtpHost='',$smtpPort='',$smtpUser='',$smtpPass=''){ - - $ret = array('status' => false); +function zeroBSCRM_mailDelivery_checkSMTPDetails( $sendFromName = '', $sendFromEmail = '', $smtpHost = '', $smtpPort = '', $smtpUser = '', $smtpPass = '' ) { + + $ret = array( 'status' => false ); #} Perms? - if (!zeroBSCRM_permsMailCampaigns()){ + if ( ! zeroBSCRM_permsMailCampaigns() ) { $ret['errors'] = 'perms'; return $ret; - + } #} Check for empties once if ( - !empty($sendFromName) && - !empty($sendFromEmail) && - !empty($smtpHost) && - !empty($smtpPort) && - !empty($smtpUser) && - !empty($smtpPass) + ! empty( $sendFromName ) && + ! empty( $sendFromEmail ) && + ! empty( $smtpHost ) && + ! empty( $smtpPort ) && + ! empty( $smtpUser ) && + ! empty( $smtpPass ) - ){ + ) { $emailWasSent = false; #} Fill these into array $smtpSettings = array( - 'host' => $smtpHost, - 'user' => $smtpUser, - 'pass' => $smtpPass, + 'host' => $smtpHost, + 'user' => $smtpUser, + 'pass' => $smtpPass, 'port' => (int) $smtpPort, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - 'security' => '' + 'security' => '', ); #} rough switch (though it'll autoswitch below on fail) - if ($smtpSettings['port'] == 465) $smtpSettings['security'] = 'ssl'; - + if ( $smtpSettings['port'] == 465 ) { + $smtpSettings['security'] = 'ssl'; + } #} This'll try as follows: #} - 1) Raw settings as provided by user/api call @@ -927,18 +1024,20 @@ function zeroBSCRM_mailDelivery_checkSMTPDetails($sendFromName='',$sendFromEmail if ( zeroBSCRM_validateEmail( $sendFromEmail ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase #} Some test text: - $emTo = $sendFromEmail; // - here we send to itself :) VALIDATORTARGET; - $emHTMLBody = zeroBSCRM_mailDelivery_generateTestHTML(true); - $emTextBody = ''; - $emSubject = '[Jetpack CRM] '.__('Mail Delivery Routine',"zero-bs-crm"); + $emTo = $sendFromEmail; // - here we send to itself :) VALIDATORTARGET; + $emHTMLBody = zeroBSCRM_mailDelivery_generateTestHTML( true ); + $emTextBody = ''; + $emSubject = '[Jetpack CRM] ' . __( 'Mail Delivery Routine', 'zero-bs-crm' ); $commonSMTPSettings = jpcrm_maildelivery_common_SMTP_settings(); if ( - isset($emHTMLBody) && !empty($emHTMLBody) && - isset($emTo) && zeroBSCRM_validateEmail($emTo) - ){ + isset( $emHTMLBody ) && ! empty( $emHTMLBody ) && + isset( $emTo ) && zeroBSCRM_validateEmail( $emTo ) + ) { - $testCount = 0; $emailDebugs = array(); $emailSettingsTried = array(); + $testCount = 0; + $emailDebugs = array(); + $emailSettingsTried = array(); #} =============================================== #} ==== 1) Raw settings as provided by user/api call #} =============================================== @@ -949,22 +1048,30 @@ function zeroBSCRM_mailDelivery_checkSMTPDetails($sendFromName='',$sendFromEmail #} go $emailDebug = zeroBSCRM_mailDelivery_sendViaSMTP( #} SMTP Settings - $smtpSettings['host'],$smtpSettings['port'],$smtpSettings['user'],$smtpSettings['pass'], - #'tls', #tls ssl - switched for option: + $smtpSettings['host'], + $smtpSettings['port'], + $smtpSettings['user'], + $smtpSettings['pass'], + #'tls', #tls ssl - switched for option: $smtpSettings['security'], - #} FROM - $sendFromEmail,$sendFromName, - #} To - $emTo,'', - #} Deets - $emSubject,$emTextBody,$emHTMLBody, - #} Following returns debug - true,true + #} FROM + $sendFromEmail, + $sendFromName, + #} To + $emTo, + '', + #} Deets + $emSubject, + $emTextBody, + $emHTMLBody, + #} Following returns debug + true, + true ); #} add to debug list + log tried - $emailDebugs[] = $emailDebug; - $emailSettingsTried[] = json_encode($smtpSettings); + $emailDebugs[] = $emailDebug; + $emailSettingsTried[] = json_encode( $smtpSettings ); #} Analysis of send @@ -973,310 +1080,345 @@ function zeroBSCRM_mailDelivery_checkSMTPDetails($sendFromName='',$sendFromEmail #success: or error: if ( str_starts_with( $emailDebug, 'error:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $emailWasSent = false; - $emailSentMsg = __('Your SMTP details do not allow mail to be sent. (A test email could not be successfully sent)',"zero-bs-crm"); + $emailWasSent = false; + $emailSentMsg = __( 'Your SMTP details do not allow mail to be sent. (A test email could not be successfully sent)', 'zero-bs-crm' ); #} various: - if ($emailDebug == 'error:SMTP connect() failed.'){ - $emailSentMsg .= " - ".__('This error suggests that your Port & Security settings are not correct, or that you have the wrong value for SMTP Host.',"zero-bs-crm"); - } - + if ( $emailDebug == 'error:SMTP connect() failed.' ) { + $emailSentMsg .= ' + ' . __( 'This error suggests that your Port & Security settings are not correct, or that you have the wrong value for SMTP Host.', 'zero-bs-crm' ); + } } elseif ( str_starts_with( $emailDebug, 'success:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $emailWasSent = true; - $emailSentMsg .= __("Success! Your SMTP details are correct. (A test email was successfully sent)","zero-bs-crm"); + $emailWasSent = true; + $emailSentMsg .= __( 'Success! Your SMTP details are correct. (A test email was successfully sent)', 'zero-bs-crm' ); - } - $testCount++; + } + ++$testCount; #} =============================================== #} ==== 2) Check settings against common settings + if such (gmail etc.) then adopt typical settings + retest #} =============================================== - if (!$emailWasSent){ + if ( ! $emailWasSent ) { - #} slow down, joe - sleep(1); + #} slow down, joe + sleep( 1 ); - $replacementHost = ''; $replacementPort = ''; $replacementSecurityMode = ''; + $replacementHost = ''; + $replacementPort = ''; + $replacementSecurityMode = ''; - #} Check host - foreach ($commonSMTPSettings as $commonSMTPKey => $commonSMTPSetting){ + #} Check host + foreach ( $commonSMTPSettings as $commonSMTPKey => $commonSMTPSetting ) { - if ($smtpSettings['host'] == $commonSMTPSetting['host']){ + if ( $smtpSettings['host'] == $commonSMTPSetting['host'] ) { - #} Override port + security mode - $replacementPort = $commonSMTPSetting['port']; - $replacementSecurityMode = $commonSMTPSetting['auth']; + #} Override port + security mode + $replacementPort = $commonSMTPSetting['port']; + $replacementSecurityMode = $commonSMTPSetting['auth']; - #} got one! - break; + #} got one! + break; - } + } + } - } + #} Try and catch common email addresses (e.g. @gmail.com) - #} Try and catch common email addresses (e.g. @gmail.com) + #} No luck? + if ( empty( $replacementPort ) && empty( $replacementSecurityMode ) ) { - #} No luck? - if (empty($replacementPort) && empty($replacementSecurityMode)){ + $mailProviderBreadcrumbs = array( + 'gmail' => array( 'gmail.com' ), + 'outlook' => array( 'outlook.com' ), + 'office365' => array( 'office365.com' ), + 'yahoo' => array( 'yahoo.com' ), + 'aol' => array( 'aol.com' ), + 'hotmail' => array( 'hotmail.com' ), + ); - $mailProviderBreadcrumbs = array( - 'gmail' => array('gmail.com'), - 'outlook' => array('outlook.com'), - 'office365' => array('office365.com'), - 'yahoo' => array('yahoo.com'), - 'aol' => array('aol.com'), - 'hotmail' => array('hotmail.com') - ); + #} dynamic :) + foreach ( $mailProviderBreadcrumbs as $settingKey => $needleArr ) { - #} dynamic :) - foreach ($mailProviderBreadcrumbs as $settingKey => $needleArr){ + if ( strpos( '#' . $sendFromEmail, $needleArr[0] ) > 0 ) { - if (strpos('#'.$sendFromEmail, $needleArr[0]) > 0){ + #} Override port + security mode + host + $replacementHost = $commonSMTPSettings[ $settingKey ]['host']; + $replacementPort = $commonSMTPSettings[ $settingKey ]['port']; + $replacementSecurityMode = $commonSMTPSettings[ $settingKey ]['auth']; - #} Override port + security mode + host - $replacementHost = $commonSMTPSettings[$settingKey]['host']; - $replacementPort = $commonSMTPSettings[$settingKey]['port']; - $replacementSecurityMode = $commonSMTPSettings[$settingKey]['auth']; + } + } - } + #} extra - ehosts.com + if ( empty( $replacementHost ) && strpos( '#' . $smtpSettings['host'], 'ehosts.com' ) > 0 ) { - } - - #} extra - ehosts.com - if (empty($replacementHost) && strpos('#'.$smtpSettings['host'],'ehosts.com') > 0){ + $replacementHost = $smtpSettings['host'];# leave as existing; + $replacementPort = 465; + $replacementSecurityMode = 'ssl'; - $replacementHost = $smtpSettings['host'];# leave as existing; - $replacementPort = 465; - $replacementSecurityMode = 'ssl'; + } + } - } + #} Override port + security mode + if ( ! empty( $replacementHost ) || ! empty( $replacementPort ) || ! empty( $replacementSecurityMode ) ) { - } + #} any? both? + if ( ! empty( $replacementHost ) ) { + $smtpSettings['host'] = $replacementHost; + } + if ( ! empty( $replacementPort ) ) { + $smtpSettings['port'] = $replacementPort; + } + if ( ! empty( $replacementSecurityMode ) ) { + $smtpSettings['security'] = $replacementSecurityMode; # tls, ssl, none + } - #} Override port + security mode - if (!empty($replacementHost) || !empty($replacementPort) || !empty($replacementSecurityMode)){ - - #} any? both? - if (!empty($replacementHost)) $smtpSettings['host'] = $replacementHost; - if (!empty($replacementPort)) $smtpSettings['port'] = $replacementPort; - if (!empty($replacementSecurityMode)) $smtpSettings['security'] = $replacementSecurityMode; # tls, ssl, none - - #} If not already tried, try that! - if (!in_array(json_encode($smtpSettings),$emailSettingsTried)){ - - // Re-test - $emailDebug = zeroBSCRM_mailDelivery_sendViaSMTP( - - #} SMTP Settings - $smtpSettings['host'],$smtpSettings['port'],$smtpSettings['user'],$smtpSettings['pass'], - #'tls', #tls ssl - switched for option: - $smtpSettings['security'], - #} FROM - $sendFromEmail,$sendFromName, - #} To - $emTo,'', - #} Deets - $emSubject,$emTextBody,$emHTMLBody, - #} Following returns debug - true,true - ); - - #} add to debug list + save tried settings - $emailDebugs[] = $emailDebug; - $emailSettingsTried[] = json_encode($smtpSettings); - - #} Analysis of send - THIS ISN'T DRY! - #success: or error: - if ( str_starts_with( $emailDebug, 'error:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - $emailWasSent = false; - $emailSentMsg = __('Your SMTP details do not allow mail to be sent. (A test email could not be successfully sent)',"zero-bs-crm"); + #} If not already tried, try that! + if ( ! in_array( json_encode( $smtpSettings ), $emailSettingsTried ) ) { + + // Re-test + $emailDebug = zeroBSCRM_mailDelivery_sendViaSMTP( + #} SMTP Settings + $smtpSettings['host'], + $smtpSettings['port'], + $smtpSettings['user'], + $smtpSettings['pass'], + #'tls', #tls ssl - switched for option: + $smtpSettings['security'], + #} FROM + $sendFromEmail, + $sendFromName, + #} To + $emTo, + '', + #} Deets + $emSubject, + $emTextBody, + $emHTMLBody, + #} Following returns debug + true, + true + ); - #} various: - if ($emailDebug == 'error:SMTP connect() failed.'){ - $emailSentMsg .= " - ".__('This error suggests that your Port & Security settings are not correct, or that you have the wrong value for SMTP Host.',"zero-bs-crm"); - } + #} add to debug list + save tried settings + $emailDebugs[] = $emailDebug; + $emailSettingsTried[] = json_encode( $smtpSettings ); - } elseif ( str_starts_with( $emailDebug, 'success:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + #} Analysis of send - THIS ISN'T DRY! + #success: or error: + if ( str_starts_with( $emailDebug, 'error:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $emailWasSent = true; - $emailSentMsg .= __("Success! Your SMTP details are correct. (A test email was successfully sent)","zero-bs-crm"); + $emailWasSent = false; + $emailSentMsg = __( 'Your SMTP details do not allow mail to be sent. (A test email could not be successfully sent)', 'zero-bs-crm' ); - } + #} various: + if ( $emailDebug == 'error:SMTP connect() failed.' ) { + $emailSentMsg .= ' + ' . __( 'This error suggests that your Port & Security settings are not correct, or that you have the wrong value for SMTP Host.', 'zero-bs-crm' ); + } + } elseif ( str_starts_with( $emailDebug, 'success:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + + $emailWasSent = true; + $emailSentMsg .= __( 'Success! Your SMTP details are correct. (A test email was successfully sent)', 'zero-bs-crm' ); - $testCount++; + } - } // if not already tested + ++$testCount; - } // if any to test + } // if not already tested - } + } // if any to test + + } #} =============================================== #} ==== 3) If no success, switch security models, (ssl/tls->tls/ssl->none) #} =============================================== - if (!$emailWasSent){ - - #} slow down, joe - sleep(1); - - #} Switch from existing - switch ($smtpSettings['security']){ - - case 'tls': - #} TLS -> SSL - $smtpSettings['port'] = 465; - $smtpSettings['security'] = 'ssl'; - break; - - case 'ssl': - #} SSL -> TLS - $smtpSettings['port'] = 587; - $smtpSettings['security'] = 'tls'; - break; - - case 'none': - #} None -> TLS - $smtpSettings['port'] = 587; - $smtpSettings['security'] = 'tls'; - break; - - case '': - #} None -> TLS - $smtpSettings['port'] = 587; - $smtpSettings['security'] = 'tls'; - break; + if ( ! $emailWasSent ) { + + #} slow down, joe + sleep( 1 ); + + #} Switch from existing + switch ( $smtpSettings['security'] ) { + + case 'tls': + #} TLS -> SSL + $smtpSettings['port'] = 465; + $smtpSettings['security'] = 'ssl'; + break; + + case 'ssl': + #} SSL -> TLS + $smtpSettings['port'] = 587; + $smtpSettings['security'] = 'tls'; + break; + + case 'none': + #} None -> TLS + $smtpSettings['port'] = 587; + $smtpSettings['security'] = 'tls'; + break; + + case '': + #} None -> TLS + $smtpSettings['port'] = 587; + $smtpSettings['security'] = 'tls'; + break; - } - - #} If not already tried, try that! - if (!in_array(json_encode($smtpSettings),$emailSettingsTried)){ - - // Re-test - $emailDebug = zeroBSCRM_mailDelivery_sendViaSMTP( - #} SMTP Settings - $smtpSettings['host'],$smtpSettings['port'],$smtpSettings['user'],$smtpSettings['pass'], - #'tls', #tls ssl - switched for option: - $smtpSettings['security'], - #} FROM - $sendFromEmail,$sendFromName, - #} To - $emTo,'', - #} Deets - $emSubject,$emTextBody,$emHTMLBody, - #} Following returns debug - true,true - ); - - #} add to debug list + save tried settings - $emailDebugs[] = $emailDebug; - $emailSettingsTried[] = json_encode($smtpSettings); - - #} Analysis of send - THIS ISN'T DRY - #success: or error: - if ( str_starts_with( $emailDebug, 'error:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - $emailWasSent = false; - $emailSentMsg = __('Your SMTP details do not allow mail to be sent. (A test email could not be successfully sent)',"zero-bs-crm"); + #} If not already tried, try that! + if ( ! in_array( json_encode( $smtpSettings ), $emailSettingsTried ) ) { + + // Re-test + $emailDebug = zeroBSCRM_mailDelivery_sendViaSMTP( + #} SMTP Settings + $smtpSettings['host'], + $smtpSettings['port'], + $smtpSettings['user'], + $smtpSettings['pass'], + #'tls', #tls ssl - switched for option: + $smtpSettings['security'], + #} FROM + $sendFromEmail, + $sendFromName, + #} To + $emTo, + '', + #} Deets + $emSubject, + $emTextBody, + $emHTMLBody, + #} Following returns debug + true, + true + ); + + #} add to debug list + save tried settings + $emailDebugs[] = $emailDebug; + $emailSettingsTried[] = json_encode( $smtpSettings ); + + #} Analysis of send - THIS ISN'T DRY + #success: or error: + if ( str_starts_with( $emailDebug, 'error:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + + $emailWasSent = false; + $emailSentMsg = __( 'Your SMTP details do not allow mail to be sent. (A test email could not be successfully sent)', 'zero-bs-crm' ); #} various: - if ($emailDebug == 'error:SMTP connect() failed.'){ - $emailSentMsg .= " - ".__('This error suggests that your Port & Security settings are not correct, or that you have the wrong value for SMTP Host.',"zero-bs-crm"); - } - - } elseif ( str_starts_with( $emailDebug, 'success:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( $emailDebug == 'error:SMTP connect() failed.' ) { + $emailSentMsg .= ' + ' . __( 'This error suggests that your Port & Security settings are not correct, or that you have the wrong value for SMTP Host.', 'zero-bs-crm' ); + } + } elseif ( str_starts_with( $emailDebug, 'success:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $emailWasSent = true; - $emailSentMsg .= __("Success! Your SMTP details are correct. (A test email was successfully sent)","zero-bs-crm"); + $emailWasSent = true; + $emailSentMsg .= __( 'Success! Your SMTP details are correct. (A test email was successfully sent)', 'zero-bs-crm' ); - } + } - $testCount++; + ++$testCount; - } // if not already tested + } // if not already tested - } + } #} =============================================== #} ==== 4) If no success, and is 587, try without TLS #} =============================================== - if (!$emailWasSent){ + if ( ! $emailWasSent ) { - #} slow down, joe - sleep(1); + #} slow down, joe + sleep( 1 ); - #} TLS? - if (isset($originalSec) && $originalSec == 'tls'){ + #} TLS? + if ( isset( $originalSec ) && $originalSec == 'tls' ) { - #} TLS -> none - $smtpSettings['port'] = 587; - $smtpSettings['security'] = ''; + #} TLS -> none + $smtpSettings['port'] = 587; + $smtpSettings['security'] = ''; - } - - #} If not already tried, try that! - if (!in_array(json_encode($smtpSettings),$emailSettingsTried)){ - - // Re-test - $emailDebug = zeroBSCRM_mailDelivery_sendViaSMTP( - #} SMTP Settings - $smtpSettings['host'],$smtpSettings['port'],$smtpSettings['user'],$smtpSettings['pass'], - #'tls', #tls ssl - switched for option: - $smtpSettings['security'], - #} FROM - $sendFromEmail,$sendFromName, - #} To - $emTo,'', - #} Deets - $emSubject,$emTextBody,$emHTMLBody, - #} Following returns debug - true,true - ); - - #} add to debug list + save tried settings - $emailDebugs[] = $emailDebug; - $emailSettingsTried[] = json_encode($smtpSettings); - - #} Analysis of send - THIS ISN'T DRY - #success: or error: - if ( str_starts_with( $emailDebug, 'error:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + } - $emailWasSent = false; - $emailSentMsg = __('Your SMTP details do not allow mail to be sent. (A test email could not be successfully sent)',"zero-bs-crm"); + #} If not already tried, try that! + if ( ! in_array( json_encode( $smtpSettings ), $emailSettingsTried ) ) { + + // Re-test + $emailDebug = zeroBSCRM_mailDelivery_sendViaSMTP( + #} SMTP Settings + $smtpSettings['host'], + $smtpSettings['port'], + $smtpSettings['user'], + $smtpSettings['pass'], + #'tls', #tls ssl - switched for option: + $smtpSettings['security'], + #} FROM + $sendFromEmail, + $sendFromName, + #} To + $emTo, + '', + #} Deets + $emSubject, + $emTextBody, + $emHTMLBody, + #} Following returns debug + true, + true + ); + + #} add to debug list + save tried settings + $emailDebugs[] = $emailDebug; + $emailSettingsTried[] = json_encode( $smtpSettings ); + + #} Analysis of send - THIS ISN'T DRY + #success: or error: + if ( str_starts_with( $emailDebug, 'error:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + + $emailWasSent = false; + $emailSentMsg = __( 'Your SMTP details do not allow mail to be sent. (A test email could not be successfully sent)', 'zero-bs-crm' ); #} various: - if ($emailDebug == 'error:SMTP connect() failed.'){ - $emailSentMsg .= " - ".__('This error suggests that your Port & Security settings are not correct, or that you have the wrong value for SMTP Host.',"zero-bs-crm"); - } - - } elseif ( str_starts_with( $emailDebug, 'success:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + if ( $emailDebug == 'error:SMTP connect() failed.' ) { + $emailSentMsg .= ' + ' . __( 'This error suggests that your Port & Security settings are not correct, or that you have the wrong value for SMTP Host.', 'zero-bs-crm' ); + } + } elseif ( str_starts_with( $emailDebug, 'success:' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $emailWasSent = true; - $emailSentMsg .= __("Success! Your SMTP details are correct. (A test email was successfully sent)","zero-bs-crm"); + $emailWasSent = true; + $emailSentMsg .= __( 'Success! Your SMTP details are correct. (A test email was successfully sent)', 'zero-bs-crm' ); - } + } - ++$testCount; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + ++$testCount; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } // if not already tested } #} Return - #} SUPER ADMIN return full debug: + #} SUPER ADMIN return full debug: # $debugArr = array('details'=>true,'sent'=>$emailWasSent,'sentmsg'=>$emailSentMsg, 'tried'=>$testCount,'debugs'=>$emailDebugs,'settingsTried'=>$emailSettingsTried); #} Normal return: // from 2.94.2 return debugs - $debugArr = array('details'=>true,'sent'=>$emailWasSent,'sentmsg'=>$emailSentMsg, 'tried'=>$testCount,'finset'=>$smtpSettings,'debugs'=>$emailDebugs); + $debugArr = array( + 'details' => true, + 'sent' => $emailWasSent, + 'sentmsg' => $emailSentMsg, + 'tried' => $testCount, + 'finset' => $smtpSettings, + 'debugs' => $emailDebugs, + ); return $debugArr; } else { # rather than erroring, just send as response - return array('details'=>true,'sent'=>false,'stage'=>3); + return array( + 'details' => true, + 'sent' => false, + 'stage' => 3, + ); } } else { @@ -1288,20 +1430,19 @@ function zeroBSCRM_mailDelivery_checkSMTPDetails($sendFromName='',$sendFromEmail ); } - // / no empties + // / no empties } else { // smt empty $ret['errors'] = 'params'; return $ret; } - } -/* -* Sends an email via Google Mail OAuth 2.0 connection +/* +* Sends an email via Google Mail OAuth 2.0 connection */ -function jpcrm_mail_delivery_send_via_gmail_oauth( $args ){ +function jpcrm_mail_delivery_send_via_gmail_oauth( $args ) { global $zbs; @@ -1322,8 +1463,22 @@ function jpcrm_mail_delivery_send_via_gmail_oauth( $args ){ 'debug' => false, 'return_debug' => false, - ); foreach ($default_args 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 ( $default_args 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 ============= // declare debug string (to return if $return_debug) $debug_string = ''; @@ -1331,11 +1486,11 @@ function jpcrm_mail_delivery_send_via_gmail_oauth( $args ){ // Load OAuth $zbs->load_oauth_handler(); - // got a usable connection profile? - if ( $zbs->oauth->connection_status( 'google_mail' ) ){ + // got a usable connection profile? + if ( $zbs->oauth->connection_status( 'google_mail' ) ) { - if ( $debug ){ - $msg = 'Viable Gmail connection found.
'; + if ( $debug ) { + $msg = 'Viable Gmail connection found.
'; $debug_string .= $msg; echo $msg; } @@ -1348,8 +1503,8 @@ function jpcrm_mail_delivery_send_via_gmail_oauth( $args ){ // build service object $service = new Google_Service_Gmail( $client ); - if ( $debug ){ - $msg = 'Gmail client and service generated.
'; + if ( $debug ) { + $msg = 'Gmail client and service generated.
'; $debug_string .= $msg; echo $msg; } @@ -1395,152 +1550,154 @@ function jpcrm_mail_delivery_send_via_gmail_oauth( $args ){ $msg->setRaw( $encoded_message ); // The special value **me** can be used to indicate the authenticated user. - $service->users_messages->send( "me", $msg ); + $service->users_messages->send( 'me', $msg ); - if ( $debug ){ - $msg = 'Gmail sent.
'; + if ( $debug ) { + $msg = 'Gmail sent.
'; $debug_string .= $msg; echo $msg; } - if ( $return_debug ){ + if ( $return_debug ) { return 'success:' . $debug_string; } return true; - } catch ( Google\Service\Exception $e ){ + } catch ( Google\Service\Exception $e ) { - if ( $debug ){ - $msg = 'Error: Google\Service\Exception:
'.$e->getMessage().'!
'; + if ( $debug ) { + $msg = 'Error: Google\Service\Exception:
' . $e->getMessage() . '!
'; $debug_string .= $msg; echo $msg; } - } - } else { // config not in go state - if ( $debug ){ - $msg = 'Gmail config not in ready state.'; - $debug_string .= $msg; - echo $msg; - } - + if ( $debug ) { + $msg = 'Gmail config not in ready state.'; + $debug_string .= $msg; + echo $msg; + } } - if ( $return_debug ){ + if ( $return_debug ) { return 'fail:' . $debug_string; } return false; - } -function zeroBSCRM_mailDelivery_retrieveACCByKey($key=-1){ +function zeroBSCRM_mailDelivery_retrieveACCByKey( $key = -1 ) { - if ($key !== -1){ + if ( $key !== -1 ) { global $zbs; - $existingZBSSMTPAccs = zeroBSCRM_getSetting('smtpaccs'); - - if (!is_array($existingZBSSMTPAccs)) return false; - if (isset($existingZBSSMTPAccs[$key])) return $existingZBSSMTPAccs[$key]; + $existingZBSSMTPAccs = zeroBSCRM_getSetting( 'smtpaccs' ); + if ( ! is_array( $existingZBSSMTPAccs ) ) { + return false; + } + if ( isset( $existingZBSSMTPAccs[ $key ] ) ) { + return $existingZBSSMTPAccs[ $key ]; + } } return false; } // returns a typed 'settings' array based on default WP setup :/ -function zeroBSCRM_mailDelivery_retrieveACCWPDefault(){ - +function zeroBSCRM_mailDelivery_retrieveACCWPDefault() { $sendFromEmail = zeroBSCRM_mailDelivery_defaultEmail(); - $sendFromName = zeroBSCRM_mailDelivery_defaultFromname(); + $sendFromName = zeroBSCRM_mailDelivery_defaultFromname(); return array( - 'mode' => 'wp_mail', - 'fromemail' => $sendFromEmail, - 'fromname' => $sendFromName, - 'replyto' => $sendFromEmail, - 'cc' => '', - 'bcc' => '', - 'veri' => time() // verified?! + 'mode' => 'wp_mail', + 'fromemail' => $sendFromEmail, + 'fromname' => $sendFromName, + 'replyto' => $sendFromEmail, + 'cc' => '', + 'bcc' => '', + 'veri' => time(), // verified?! - ); + ); } -function zeroBSCRM_mailDelivery_retrieveDefaultMDAcc(){ +function zeroBSCRM_mailDelivery_retrieveDefaultMDAcc() { // see if a default is set $defaultKey = zeroBSCRM_getMailDeliveryDefault(); - if (!empty($defaultKey)){ + if ( ! empty( $defaultKey ) ) { - // using key, get settings - $mailSettings = zeroBSCRM_mailDelivery_retrieveACCByKey($defaultKey); - - if (is_array($mailSettings)) return $mailSettings; + // using key, get settings + $mailSettings = zeroBSCRM_mailDelivery_retrieveACCByKey( $defaultKey ); + if ( is_array( $mailSettings ) ) { + return $mailSettings; } + } return false; } // makes a simple array key for this index, comparing to existing :) // some kind of semi-lazy permalink gen... lol @ self (though works) -function zeroBSCRM_mailDelivery_makeKey($accDeets=array()){ +function zeroBSCRM_mailDelivery_makeKey( $accDeets = array() ) { - if (is_array($accDeets)){ + if ( is_array( $accDeets ) ) { $str = ''; // should always be set - if (isset($accDeets['fromemail'])) $str = $accDeets['fromemail']; - if (empty($str) && isset($accDeets['fromname'])) $str .= ':'.$accDeets['fromname']; + if ( isset( $accDeets['fromemail'] ) ) { + $str = $accDeets['fromemail']; + } + if ( empty( $str ) && isset( $accDeets['fromname'] ) ) { + $str .= ':' . $accDeets['fromname']; + } - if (!empty($str)){ + if ( ! empty( $str ) ) { // quick replaces - $str = str_replace('@','-',strtolower($str)); - $str = str_replace('.','-',$str); - $str = str_replace(':','-',$str); - $str = str_replace(' ','-',$str); - $str = str_replace('--','-',$str); + $str = str_replace( '@', '-', strtolower( $str ) ); + $str = str_replace( '.', '-', $str ); + $str = str_replace( ':', '-', $str ); + $str = str_replace( ' ', '-', $str ); + $str = str_replace( '--', '-', $str ); // compare global $zbs; - $existingZBSSMTPAccs = zeroBSCRM_getSetting('smtpaccs'); + $existingZBSSMTPAccs = zeroBSCRM_getSetting( 'smtpaccs' ); // check + append - if (isset($existingZBSSMTPAccs[$str])){ + if ( isset( $existingZBSSMTPAccs[ $str ] ) ) { - $extraNo = 1; $testStr = $str; - while (isset($existingZBSSMTPAccs[$testStr]) && $extraNo < 50){ - $extraNo++; - $testStr = $str.'--'.$extraNo; + $extraNo = 1; + $testStr = $str; + while ( isset( $existingZBSSMTPAccs[ $testStr ] ) && $extraNo < 50 ) { + ++$extraNo; + $testStr = $str . '--' . $extraNo; } // any luck? - if ($extraNo < 50) return $testStr; - + if ( $extraNo < 50 ) { + return $testStr; + } } else { - + // all good, return return $str; } - - } - } return false; } // unencrypts password, but isn't obvious about it... lol?! -function zeroBSCRM_mailDelivery_retKeyData( $str = '' ){ +function zeroBSCRM_mailDelivery_retKeyData( $str = '' ) { global $zbs; @@ -1549,40 +1706,41 @@ function zeroBSCRM_mailDelivery_retKeyData( $str = '' ){ // decrypt password: return $zbs->encryption->decrypt( $str, 'smtp' ); - } // port check -function zeroBSCRM_mailDelivery_checkPort($port=false,$host='portquiz.net'){ - - //$host = 'portquiz.net'; - $errno = ''; +function zeroBSCRM_mailDelivery_checkPort( $port = false, $host = 'portquiz.net' ) { + + // $host = 'portquiz.net'; + $errno = ''; $errstr = ''; - if (empty($host)) $host = 'portquiz.net'; + if ( empty( $host ) ) { + $host = 'portquiz.net'; + } - $connection = @fsockopen($host, $port, $errno, $errstr, 5); + $connection = @fsockopen( $host, $port, $errno, $errstr, 5 ); - if (is_resource($connection)){ - fclose($connection); - return array(true,$errno,$errstr); + if ( is_resource( $connection ) ) { + fclose( $connection ); + return array( true, $errno, $errstr ); } - return array(false,$errno,$errstr); - + return array( false, $errno, $errstr ); } -/* ====================================================== - Page/Shortcode stuff - ====================================================== */ -function zeroBSCRM_mailDelivery_unsubPage(){ +/* +====================================================== + Page/Shortcode stuff + ====================================================== */ +function zeroBSCRM_mailDelivery_unsubPage() { // this catches unsubs (managed mc2) - do_action('zerobscrm_catch_unsubs'); - -} -add_shortcode('jetpackcrm_unsubscribe', 'zeroBSCRM_mailDelivery_unsubPage'); -add_shortcode('zerobscrm_unsubscribe', 'zeroBSCRM_mailDelivery_unsubPage'); -/* ====================================================== - / Page/Shortcode stuff - ====================================================== */ + do_action( 'zerobscrm_catch_unsubs' ); +} +add_shortcode( 'jetpackcrm_unsubscribe', 'zeroBSCRM_mailDelivery_unsubPage' ); +add_shortcode( 'zerobscrm_unsubscribe', 'zeroBSCRM_mailDelivery_unsubPage' ); +/* +====================================================== + / Page/Shortcode stuff + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MailTracking.php b/projects/plugins/crm/includes/ZeroBSCRM.MailTracking.php index dd7588b0ff7a..4086e3650ff1 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MailTracking.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MailTracking.php @@ -1,5 +1,5 @@ -'; - //this surely needs a hash which is decoded via PHP side.. - $tracker = site_url() . '?zbspostman=' . urlencode($hash); - $trackingImg = ''; - - //Add the tracker to the message. + // Add the tracker to the message. // first we try and jam into , if none, (THATS WEIRD), we just append... - if (strpos($messageHTML,' 0){ + if ( strpos( $messageHTML, ' 0 ) { - // prepend get_var($sql); - $max_thread++; + if ( $thread == -1 ) { + // then we are making a new thread. Otherwise, it will be passed via the function / other send boxes + $sql = 'SELECT MAX(zbsmail_sender_thread) as max_thread FROM ' . $ZBSCRM_t['system_mail_hist']; + $max_thread = (int) $wpdb->get_var( $sql ); + ++$max_thread; $thread = $max_thread; } - $email_data = array( - 'zbs_site' => -1, - 'zbs_team' => -1, - 'zbs_owner' => -1, - 'zbsmail_type' => $emailTypeID, // prev zbs_emailID - 'zbsmail_sent' => -1, - 'zbsmail_assoc_objid' => $associatedObjID, // prev zbsmail_assoc_objid - 'zbsmail_sender_email' => $senderEmailAddress, // prev zbsmail_sender_email - 'zbsmail_subject' => $emailSubject, + $email_data = array( + 'zbs_site' => -1, + 'zbs_team' => -1, + 'zbs_owner' => -1, + 'zbsmail_type' => $emailTypeID, // prev zbs_emailID + 'zbsmail_sent' => -1, + 'zbsmail_assoc_objid' => $associatedObjID, // prev zbsmail_assoc_objid + 'zbsmail_sender_email' => $senderEmailAddress, // prev zbsmail_sender_email + 'zbsmail_subject' => $emailSubject, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase 'zbsmail_content' => $emailContent, // THIS IS FREE of formatting e.g. not put through a specific format (wp_kses) - do that a level up/when passing content - 'zbsmail_sender_wpid' => $senderWPID, // prev zbsmail_sender_wpid - 'zbsmail_target_objid' => $targetObjID, // prev zbsmail_target_objid - 'zbsmail_hash' => $hash, + 'zbsmail_sender_wpid' => $senderWPID, // prev zbsmail_sender_wpid + 'zbsmail_target_objid' => $targetObjID, // prev zbsmail_target_objid + 'zbsmail_hash' => $hash, - 'zbsmail_status' => $in_or_out, - 'zbsmail_starred' => 0, + 'zbsmail_status' => $in_or_out, + 'zbsmail_starred' => 0, - 'zbsmail_sender_thread' => $thread, - 'zbsmail_receiver_email' => $email_to, + 'zbsmail_sender_thread' => $thread, + 'zbsmail_receiver_email' => $email_to, // maildelivery method 'zbsmail_sender_maildelivery_key' => $mailDeliveryMethod, - - 'zbsmail_lastopened' => 0, - 'zbsmail_lastclicked' => 0, - 'zbsmail_created' => time() + 'zbsmail_lastopened' => 0, + 'zbsmail_lastclicked' => 0, + 'zbsmail_created' => time(), ); - if ($wpdb->insert( - $ZBSCRM_t['system_mail_hist'], - $email_data, - array( - '%d', //zbs_site - '%d', //zbs_team - '%d', //zbs_owner - '%d', //zbs_emailID - '%d', //sent - '%d', //item - '%s', //email - '%s', //subject - '%s', //body - '%d', //who - '%d', //userID - '%s', //hash - - '%s', //status (inbox, sent, draft, scheduled) - '%d', //0 = not starred, 1 = starred - - '%d', //the thread we are sending - '%s', //sent to which email - - '%s', //mail delivery method key - - '%d', //last opened - '%d', //lastclicked - '%d', //created - ) - ) > 0){ + if ( $wpdb->insert( + $ZBSCRM_t['system_mail_hist'], + $email_data, + array( + '%d', // zbs_site + '%d', // zbs_team + '%d', // zbs_owner + '%d', // zbs_emailID + '%d', // sent + '%d', // item + '%s', // email + '%s', // subject + '%s', // body + '%d', // who + '%d', // userID + '%s', // hash + + '%s', // status (inbox, sent, draft, scheduled) + '%d', // 0 = not starred, 1 = starred + + '%d', // the thread we are sending + '%s', // sent to which email + + '%s', // mail delivery method key + + '%d', // last opened + '%d', // lastclicked + '%d', // created + ) + ) > 0 ) { // inserted, let's move on - + // return id? - if (!$returnHash) $newSysTemplateHist = $wpdb->insert_id; + if ( ! $returnHash ) { + $newSysTemplateHist = $wpdb->insert_id; + } // otherwise return hash (used in tracking pixel) return $hash; @@ -269,208 +271,194 @@ function zeroBSCRM_mailTracking_logEmail($emailTypeID=-1, $targetObjID=-1, $send // This function updates line to say 'SENT' // it just updates the 'sent' flag :) -function zeroBSCRM_mailTracking_logSend($hash='',$ID=-1){ +function zeroBSCRM_mailTracking_logSend( $hash = '', $ID = -1 ) { global $wpdb, $ZBSCRM_t; // build where - $whereArr = array(); $whereTypeArr = array(); - if (!empty($hash)) { + $whereArr = array(); + $whereTypeArr = array(); + if ( ! empty( $hash ) ) { $whereArr['zbsmail_hash'] = $hash; - $whereTypeArr[] = '%s'; + $whereTypeArr[] = '%s'; } - if (!empty($ID) && $ID > 0) { + if ( ! empty( $ID ) && $ID > 0 ) { $whereArr['ID'] = $ID; $whereTypeArr[] = '%d'; } - if (count($whereArr) > 0){ + if ( count( $whereArr ) > 0 ) { - if ($wpdb->update($ZBSCRM_t['system_mail_hist'], - array( - 'zbsmail_sent' => 1, - ), - $whereArr, - $whereTypeArr, - array( - '%d' - ) - ) !== false){ + if ( $wpdb->update( + $ZBSCRM_t['system_mail_hist'], + array( + 'zbsmail_sent' => 1, + ), + $whereArr, + $whereTypeArr, + array( + '%d', + ) + ) !== false ) { - return true; - - } + return true; + } } return false; } - -// This function updates line to say 'opened' ++increments opened and updates zbsmail_lastopened -function zeroBSCRM_mailTracking_logOpen($hash='', $ID=-1, $newOpenedCount = 1, $firstOpen = 0){ +// This function updates line to say 'opened' ++increments opened and updates zbsmail_lastopened +function zeroBSCRM_mailTracking_logOpen( $hash = '', $ID = -1, $newOpenedCount = 1, $firstOpen = 0 ) { global $wpdb, $ZBSCRM_t; - - // build where - $whereArr = array(); $whereTypeArr = array(); - if (!empty($hash)) { + $whereArr = array(); + $whereTypeArr = array(); + if ( ! empty( $hash ) ) { $whereArr['zbsmail_hash'] = $hash; - $whereTypeArr[] = '%s'; + $whereTypeArr[] = '%s'; } - if (!empty($ID) && $ID > 0) { + if ( ! empty( $ID ) && $ID > 0 ) { $whereArr['ID'] = $ID; $whereTypeArr[] = '%d'; } #} so we only record the first opened the once. - $data = array( - 'zbsmail_opened' => $newOpenedCount, - 'zbsmail_lastopened' => time() + $data = array( + 'zbsmail_opened' => $newOpenedCount, + 'zbsmail_lastopened' => time(), ); - $data_format = array( + $data_format = array( + '%d', '%d', - '%d' ); - - - - if($firstOpen == 0){ + if ( $firstOpen == 0 ) { $data['zbsmail_firstopened'] = time(); - $data_format[] = '%d'; + $data_format[] = '%d'; } - if (count($whereArr) > 0){ - - - /* - - $wpdb->update( - 'table', - array( - 'column1' => 'value1', // string - 'column2' => 'value2' // integer (number) - ), - array( 'ID' => 1 ), - array( - '%s', // value1 - '%d' // value2 - ), - array( '%d' ) -); - - */ - - //this had a bug in the whereArr and data_format were the wrong way around (to check in core branch) - $rows_updated = $wpdb->update($ZBSCRM_t['system_mail_hist'], - $data, - $whereArr, - $data_format, - $whereTypeArr + if ( count( $whereArr ) > 0 ) { + + /* + $wpdb->update( + 'table', + array( + 'column1' => 'value1', // string + 'column2' => 'value2' // integer (number) + ), + array( 'ID' => 1 ), + array( + '%s', // value1 + '%d' // value2 + ), + array( '%d' ) ); - if($rows_updated){ + */ + + // this had a bug in the whereArr and data_format were the wrong way around (to check in core branch) + $rows_updated = $wpdb->update( + $ZBSCRM_t['system_mail_hist'], + $data, + $whereArr, + $data_format, + $whereTypeArr + ); + + if ( $rows_updated ) { return true; } - } return false; } - - - - - - - -function zeroBSCRM_get_email_history($page=0, $limit=50, $userID = -1, $type='', $email=-1, $thread=false, $threadID = -1, $star=false, $justCust = true){ +function zeroBSCRM_get_email_history( $page = 0, $limit = 50, $userID = -1, $type = '', $email = -1, $thread = false, $threadID = -1, $star = false, $justCust = true ) { global $wpdb, $ZBSCRM_t; - $order = 'DESC'; - $extra_sql = ""; - if($userID > 0){ - $extra_sql = $wpdb->prepare(" WHERE zbsmail_target_objid = %d", $userID); + $order = 'DESC'; + $extra_sql = ''; + if ( $userID > 0 ) { + $extra_sql = $wpdb->prepare( ' WHERE zbsmail_target_objid = %d', $userID ); } - if($type != ''){ + if ( $type != '' ) { #} this is our inboxes condition here for zbsmail_target_objid > 0 - $extra_sql = $wpdb->prepare(" WHERE zbsmail_status = %s AND zbsmail_target_objid >= 0 AND zbsmail_sender_wpid >= 0", $type); + $extra_sql = $wpdb->prepare( ' WHERE zbsmail_status = %s AND zbsmail_target_objid >= 0 AND zbsmail_sender_wpid >= 0', $type ); } - if($email > 0){ - $extra_sql = $wpdb->prepare(" WHERE ID = %d", $email); + if ( $email > 0 ) { + $extra_sql = $wpdb->prepare( ' WHERE ID = %d', $email ); } - if($thread){ - $extra_sql .= " GROUP BY zbsmail_sender_thread"; + if ( $thread ) { + $extra_sql .= ' GROUP BY zbsmail_sender_thread'; } - if($threadID >= 0){ - $extra_sql = $wpdb->prepare(" WHERE zbsmail_sender_thread = %d", $threadID); + if ( $threadID >= 0 ) { + $extra_sql = $wpdb->prepare( ' WHERE zbsmail_sender_thread = %d', $threadID ); } - if($threadID >= 0 && $userID > 0){ - $extra_sql = $wpdb->prepare(" WHERE zbsmail_target_objid = %d AND zbsmail_sender_thread = %d", $userID, $threadID); - $order = 'ASC'; + if ( $threadID >= 0 && $userID > 0 ) { + $extra_sql = $wpdb->prepare( ' WHERE zbsmail_target_objid = %d AND zbsmail_sender_thread = %d', $userID, $threadID ); + $order = 'ASC'; } - if($star && $thread){ - $extra_sql = " WHERE zbsmail_starred = 1 GROUP BY zbsmail_sender_thread"; + if ( $star && $thread ) { + $extra_sql = ' WHERE zbsmail_starred = 1 GROUP BY zbsmail_sender_thread'; } - $limit = (int)$limit; $page = (int)$page; - $sql = "SELECT * FROM " . $ZBSCRM_t['system_mail_hist'] . $extra_sql . " ORDER BY zbsmail_created ".$order." LIMIT $limit OFFSET $page"; - - - $r = $wpdb->get_results($sql); - + $limit = (int) $limit; + $page = (int) $page; + $sql = 'SELECT * FROM ' . $ZBSCRM_t['system_mail_hist'] . $extra_sql . ' ORDER BY zbsmail_created ' . $order . " LIMIT $limit OFFSET $page"; + $r = $wpdb->get_results( $sql ); return $r; } -function zeroBSCRM_mailDelivery_getTemplateStats($ID){ - //get our stats... +function zeroBSCRM_mailDelivery_getTemplateStats( $ID ) { + // get our stats... global $wpdb, $ZBSCRM_t; - $sql = $wpdb->prepare("SELECT count(ID) as zbs_sent, count(zbsmail_opened) as zbs_opened, count(zbsmail_clicked) as zbs_clicked, sum(zbsmail_opened) as total_opens, sum(zbsmail_clicked) as total_clicks FROM " . $ZBSCRM_t['system_mail_hist'] . " WHERE zbsmail_type = %d", $ID); - $r = $wpdb->get_results($sql); - - if(is_array($r) && $r[0]->zbs_sent > 0){ - $sent = $r[0]->zbs_sent; - $open = round(100*($r[0]->zbs_opened / $r[0]->zbs_sent),0); - $click = round(100*($r[0]->zbs_clicked / $r[0]->zbs_sent),0); - esc_html_e($sent . " SENT, ".$open."% OPENED", 'zero-bs-crm'); - }else{ - esc_html_e("0 SENT, 0% OPENED", 'zero-bs-crm'); + $sql = $wpdb->prepare( 'SELECT count(ID) as zbs_sent, count(zbsmail_opened) as zbs_opened, count(zbsmail_clicked) as zbs_clicked, sum(zbsmail_opened) as total_opens, sum(zbsmail_clicked) as total_clicks FROM ' . $ZBSCRM_t['system_mail_hist'] . ' WHERE zbsmail_type = %d', $ID ); + $r = $wpdb->get_results( $sql ); + + if ( is_array( $r ) && $r[0]->zbs_sent > 0 ) { + $sent = $r[0]->zbs_sent; + $open = round( 100 * ( $r[0]->zbs_opened / $r[0]->zbs_sent ), 0 ); + $click = round( 100 * ( $r[0]->zbs_clicked / $r[0]->zbs_sent ), 0 ); + esc_html_e( $sent . ' SENT, ' . $open . '% OPENED', 'zero-bs-crm' ); + } else { + esc_html_e( '0 SENT, 0% OPENED', 'zero-bs-crm' ); } } -function zeroBSCRM_get_email_status($ID){ - //gets whether an email is active or not (i.e. client portal) +function zeroBSCRM_get_email_status( $ID ) { + // gets whether an email is active or not (i.e. client portal) global $wpdb, $ZBSCRM_t; - $sql = $wpdb->prepare("SELECT zbsmail_active FROM " . $ZBSCRM_t['system_mail_templates'] . " WHERE zbsmail_id = %d", $ID); - $r = $wpdb->get_results($sql); + $sql = $wpdb->prepare( 'SELECT zbsmail_active FROM ' . $ZBSCRM_t['system_mail_templates'] . ' WHERE zbsmail_id = %d', $ID ); + $r = $wpdb->get_results( $sql ); if ( isset( $r[0] ) && $r[0]->zbsmail_active == 1 ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual -- strict comparison breaks functionality. return true; - }else{ + } else { return false; } } -//gets an email line based on a passed hash -function zeroBSCRM_mailTracking_getEmailFromHash($hash=''){ - +// gets an email line based on a passed hash +function zeroBSCRM_mailTracking_getEmailFromHash( $hash = '' ) { + global $wpdb, $ZBSCRM_t; - $sql = $wpdb->prepare("SELECT * FROM " . $ZBSCRM_t['system_mail_hist'] . " WHERE zbsmail_hash = %s", $hash); - $r = $wpdb->get_row($sql,'ARRAY_A'); + $sql = $wpdb->prepare( 'SELECT * FROM ' . $ZBSCRM_t['system_mail_hist'] . ' WHERE zbsmail_hash = %s', $hash ); + $r = $wpdb->get_row( $sql, 'ARRAY_A' ); - if (is_array($r)) return $r; + if ( is_array( $r ) ) { + return $r; + } return false; - } - -/* ====================================================== - / Email tracking functions - ====================================================== */ +/* +====================================================== + / Email tracking functions + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBox.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBox.php index a7af6509a137..4dbdf42203a2 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBox.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBox.php @@ -1,5 +1,5 @@ - - since 2.98.7 - public $typeInt = false; // this was added late in DAL2 migration (28/04/18) but we should migrate to this over the other $postType etc. (started with Metaboxes.TagManger.php) + // default positions + public $metaboxScreen = false; // set in child class zerobs_contact + public $metaboxScreens = false; // added v3.0 - if set and is array, this'll override metaboxScreen in terms of WHERE it's shown - allowing multiple exposed points from one metabox (e.g. contacts + co's) - set in child class zerobs_contact + public $metaboxArea = false; // set in child class normal + public $metaboxLocation = false; // set in child class high - // v3.0 this was renamed objType public $postType = false; // set in child class 'zerobs_customer' // ONLY USED IN save funcs etc. maybe, potentially just legacy now. - public $objType = false; // set in child class 'contact' // ONLY USED IN save funcs etc. maybe, potentially just legacy now. - public $metaboxID = false; // set in child class 'zerobs-customer-edit'; - public $metaboxTitle = ''; // set in child class __('Customer Details',"zero-bs-crm") - public $metaboxIcon = ''; // Semantic ui icon e.g. "heartbeat" = - since 2.98.7 - - // default positions - public $metaboxScreen = false; // set in child class zerobs_contact - public $metaboxScreens = false; // added v3.0 - if set and is array, this'll override metaboxScreen in terms of WHERE it's shown - allowing multiple exposed points from one metabox (e.g. contacts + co's) - set in child class zerobs_contact - public $metaboxArea = false; // set in child class normal - public $metaboxLocation = false; // set in child class high - - // style choices - public $headless = false; // hides header? - public $metaboxClasses = ''; // extra classes to add to the wrappers + // style choices + public $headless = false; // hides header? + public $metaboxClasses = ''; // extra classes to add to the wrappers - // save options - public $saveOrder = 10; // priority for this metabox to save. MAIN RECORDS use 1 so that later metaboxes can gain ID from newly inserted via global - public $updateMessages = array(); + // save options + public $saveOrder = 10; // priority for this metabox to save. MAIN RECORDS use 1 so that later metaboxes can gain ID from newly inserted via global + public $updateMessages = array(); - // hide/show - public $live = true; // switching this to false before initMetabox will STOP it loading (allows for 'checks') + // hide/show + public $live = true; // switching this to false before initMetabox will STOP it loading (allows for 'checks') - // screen options - defaults - note these are also used in add_meta_box for empties - public $capabilities = array( + // screen options - defaults - note these are also used in add_meta_box for empties + public $capabilities = array( - 'can_hide' => true, // can be hidden - 'areas' => array('normal','side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true, // can be rearranged - 'hide_on_new' => false, // if this is true, on "new" edit's this'll hide (e.g. logs no point till added) + 'can_hide' => true, // can be hidden + 'areas' => array( 'normal', 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be rearranged + 'hide_on_new' => false, // if this is true, on "new" edit's this'll hide (e.g. logs no point till added) - ); + ); - //public function __construct( $plugin_file ) { - public function initMetabox(){ + // public function __construct( $plugin_file ) { + public function initMetabox() { - // catch old screen's and translate (in few rare cases) - if ($this->metaboxScreen == 'zerobs_edit_contact') $this->metaboxScreen = 'zbs-add-edit-contact-edit'; - - if ($this->live){ + // catch old screen's and translate (in few rare cases) + if ( $this->metaboxScreen == 'zerobs_edit_contact' ) { + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; + } + + if ( $this->live ) { + + // lazy hackaround for now, can be more classy later. + if ( ! empty( $this->metaboxIcon ) ) { + $this->metaboxTitle = ' ' . $this->metaboxTitle; + } - // lazy hackaround for now, can be more classy later. - if (!empty($this->metaboxIcon)) $this->metaboxTitle = ' '.$this->metaboxTitle; + // self::$instance = $this; - //self::$instance = $this; + // Create on init, for zbs metaboxes, rather than: add_action( 'add_meta_boxes', array( $this, 'create_meta_box' ) ); + $this->create_meta_box(); - // Create on init, for zbs metaboxes, rather than: add_action( 'add_meta_boxes', array( $this, 'create_meta_box' ) ); - $this->create_meta_box(); - - // add save func, even if will be blank :) - // WP was using filters, I'll move to actions (makes more sense to me, having read actions vs filters) - //add_filter( 'zerobs_save_'.$this->postType, array( $this, 'save_meta_box' ), 10, 2 ); + // add save func, even if will be blank :) + // WP was using filters, I'll move to actions (makes more sense to me, having read actions vs filters) + // add_filter( 'zerobs_save_'.$this->postType, array( $this, 'save_meta_box' ), 10, 2 ); if ( $this->objType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - add_action( 'zerobs_save_'.$this->objType, array( $this, 'save_meta_box' ), $this->saveOrder, 2 ); + add_action( 'zerobs_save_' . $this->objType, array( $this, 'save_meta_box' ), $this->saveOrder, 2 ); } - // This is fired by edit page do_action + // This is fired by edit page do_action - // this is then set to fire after ALL other save funcs :) - // ... by way of a 999 priority + // this is then set to fire after ALL other save funcs :) + // ... by way of a 999 priority if ( $this->objType ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - add_action( 'zerobs_save_'.$this->objType, array( $this, 'post_save_meta_box' ), 999, 2 ); + add_action( 'zerobs_save_' . $this->objType, array( $this, 'post_save_meta_box' ), 999, 2 ); } - } - - - } - - public function create_meta_box() { - - if (isset($this->metaboxScreens) && is_array($this->metaboxScreens)){ - - foreach ($this->metaboxScreens as $metaboxScreen){ - - // shown in multiple screens, so add for each - - if (!empty($metaboxScreen)){ - - zeroBSCRM_add_meta_box( - $this->metaboxID, - $this->metaboxTitle, - array( $this, 'print_meta_box' ), - $metaboxScreen, //$this->metaboxScreen, - $this->metaboxArea, - $this->metaboxLocation, - array(), - $this->headless, - $this->metaboxClasses, - $this->capabilities - ); + } + } - } - } + public function create_meta_box() { + if ( isset( $this->metaboxScreens ) && is_array( $this->metaboxScreens ) ) { - } else { + foreach ( $this->metaboxScreens as $metaboxScreen ) { - // normal, only shown in one place - zeroBSCRM_add_meta_box( - $this->metaboxID, - $this->metaboxTitle, - array( $this, 'print_meta_box' ), - $this->metaboxScreen, - $this->metaboxArea, - $this->metaboxLocation, - array(), - $this->headless, - $this->metaboxClasses, - $this->capabilities - ); + // shown in multiple screens, so add for each - } - - } + if ( ! empty( $metaboxScreen ) ) { - // use this to output data (post nonce :) - public function html($obj,$metabox){ + zeroBSCRM_add_meta_box( + $this->metaboxID, + $this->metaboxTitle, + array( $this, 'print_meta_box' ), + $metaboxScreen, // $this->metaboxScreen, + $this->metaboxArea, + $this->metaboxLocation, + array(), + $this->headless, + $this->metaboxClasses, + $this->capabilities + ); - // child class will print box here + } + } + } else { + + // normal, only shown in one place + zeroBSCRM_add_meta_box( + $this->metaboxID, + $this->metaboxTitle, + array( $this, 'print_meta_box' ), + $this->metaboxScreen, + $this->metaboxArea, + $this->metaboxLocation, + array(), + $this->headless, + $this->metaboxClasses, + $this->capabilities + ); - } + } + } - /* Not actually used yet... wh used $zbs->pageMessages for brevity, but will work (though will output IN a metabox) - public function html_msgs($obj,$metabox){ + // use this to output data (post nonce :) + public function html( $obj, $metabox ) { - // This outputs any html msgs directly (probably called by the edit class above) - if (is_array($this->updateMessages) && count($this->updateMessages) > 0) foreach ($this->updateMessages as $m) echo $m; - }*/ + // child class will print box here + } - // use this to save data in child classes (nonce-checked :) - public function save_data($objID,$obj){ + /* + Not actually used yet... wh used $zbs->pageMessages for brevity, but will work (though will output IN a metabox) + public function html_msgs($obj,$metabox){ - // save data + // This outputs any html msgs directly (probably called by the edit class above) + if (is_array($this->updateMessages) && count($this->updateMessages) > 0) foreach ($this->updateMessages as $m) echo $m; + }*/ - } + // use this to save data in child classes (nonce-checked :) + public function save_data( $objID, $obj ) { - // use this for post-save data in child classes (nonce-checked :) - public function post_save_data($objID,$obj){ + // save data + } - // do any actions needed after all metaboxes have saved data + // use this for post-save data in child classes (nonce-checked :) + public function post_save_data( $objID, $obj ) { - } + // do any actions needed after all metaboxes have saved data + } - public function print_meta_box( $obj, $metabox ) { + public function print_meta_box( $obj, $metabox ) { - // nonce output by parent class + // nonce output by parent class if ( $this->metaboxID ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - wp_nonce_field( 'save_' . $this->metaboxID, $this->metaboxID . '_nonce' ); + wp_nonce_field( 'save_' . $this->metaboxID, $this->metaboxID . '_nonce' ); } - $this->html($obj,$metabox); - - - } + $this->html( $obj, $metabox ); + } - // Parent class only, let children class simply use func 'save_data' - public function save_meta_box( $objID, $obj ) { + // Parent class only, let children class simply use func 'save_data' + public function save_meta_box( $objID, $obj ) { - // metabox set? + // metabox set? if ( ! $this->metaboxID || ! isset( $_POST[ $this->metaboxID . '_nonce' ] ) || empty( $_POST[ $this->metaboxID . '_nonce' ] ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase return; } - // autosave? (legacy, probswill never do as our own page now) - if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ){ return; } - // final nonce check - if (isset($_POST[$this->metaboxID . '_nonce']) && wp_verify_nonce( $_POST[ $this->metaboxID . '_nonce' ], 'save_' . $this->metaboxID )){ + // autosave? (legacy, probswill never do as our own page now) + if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { + return; } + // final nonce check + if ( isset( $_POST[ $this->metaboxID . '_nonce' ] ) && wp_verify_nonce( $_POST[ $this->metaboxID . '_nonce' ], 'save_' . $this->metaboxID ) ) { + + // here we check if another metabox (e.g. main save record) has fired first + inserted, leaving us an id:) + global $zbsJustInsertedMetaboxID; + if ( $objID == -1 && isset( $zbsJustInsertedMetaboxID ) && ! empty( $zbsJustInsertedMetaboxID ) && $zbsJustInsertedMetaboxID > 0 ) { + $objID = $zbsJustInsertedMetaboxID; + } - // here we check if another metabox (e.g. main save record) has fired first + inserted, leaving us an id:) - global $zbsJustInsertedMetaboxID; - if ($objID == -1 && isset($zbsJustInsertedMetaboxID) && !empty($zbsJustInsertedMetaboxID) && $zbsJustInsertedMetaboxID > 0) $objID = $zbsJustInsertedMetaboxID; + // Good to save, this has basically 'checked' the metabox nonce for us, so avoids child-classes having to :) + $this->save_data( $objID, $obj ); - // Good to save, this has basically 'checked' the metabox nonce for us, so avoids child-classes having to :) - $this->save_data($objID,$obj); - - } + } - return $obj; - } + return $obj; + } - // Parent class only, let children class simply use func 'post_save_data' - public function post_save_meta_box( $objID, $obj ) { + // Parent class only, let children class simply use func 'post_save_data' + public function post_save_meta_box( $objID, $obj ) { - // simply fires this - $this->post_save_data($objID,$obj); + // simply fires this + $this->post_save_data( $objID, $obj ); - return $obj; - } + return $obj; + } - // outputs zbs dal notice stack: - public function dalNoticeMessage($messages=array()){ + // outputs zbs dal notice stack: + public function dalNoticeMessage( $messages = array() ) { - $this->dalOutputMessage($messages,'notice',__('General Notice','zero-bs-crm')); + $this->dalOutputMessage( $messages, 'notice', __( 'General Notice', 'zero-bs-crm' ) ); + } - } + // outputs zbs dal error stack: + public function dalErrorMessage( $messages = array() ) { - // outputs zbs dal error stack: - public function dalErrorMessage($messages=array()){ + $this->dalOutputMessage( $messages, 'error', __( 'General Error', 'zero-bs-crm' ) ); + } - $this->dalOutputMessage($messages,'error',__('General Error','zero-bs-crm')); + // outputs html for a message stack + public function dalOutputMessage( $messages = array(), $type = 'error', $fallback = '' ) { + + global $zbs; + + // type switch + switch ( $type ) { + + case 'notice': + $classes = 'info green mini'; + if ( empty( $fallback ) ) { + $fallback = __( 'General Notice', 'zero-bs-crm' ); + } + $msgHeader = __( 'Update Notice:', 'zero-bs-crm' ); + $ico = 'sticky note outline'; + $id = 'generalNotice'; + break; + + // errs (Default) + default: + $classes = 'info orange mini'; + if ( empty( $fallback ) ) { + $fallback = __( 'General Error', 'zero-bs-crm' ); + } + $msgHeader = $zbs->DAL->typeStr( $zbs->DAL->objTypeKey( $this->objType ) ) . ' ' . __( 'Could not be saved', 'zero-bs-crm' ); + $ico = 'red frown outline'; + $id = 'couldNotUpdate'; + break; - } + } + + $msgDetail = ''; + if ( is_array( $messages ) ) { + foreach ( $messages as $message ) { - // outputs html for a message stack - public function dalOutputMessage($messages=array(),$type='error',$fallback=''){ + // < v3.0 + $messageStr = $message; - global $zbs; + // v3.0+ $message becomes a more thoughtful array + if ( is_array( $message ) ) { - // type switch - switch ($type){ + // set this to stop php warnings if not got 'str' attr + $messageStr = $fallback; - case 'notice': - $classes = 'info green mini'; - if (empty($fallback)) $fallback = __('General Notice','zero-bs-crm'); - $msgHeader = __('Update Notice:','zero-bs-crm'); - $ico = 'sticky note outline'; - $id = 'generalNotice'; - break; + // retrieve + if ( isset( $message['str'] ) ) { + $messageStr = $message['str']; + } + } - // errs (Default) - default: - $classes = 'info orange mini'; - if (empty($fallback)) $fallback = __('General Error','zero-bs-crm'); - $msgHeader = $zbs->DAL->typeStr($zbs->DAL->objTypeKey($this->objType)).' '.__('Could not be saved',"zero-bs-crm"); - $ico = 'red frown outline'; - $id = 'couldNotUpdate'; - break; + $msgDetail .= $messageStr . '
'; + } + } + + // genericified from DAL3.0 + $msg = zeroBSCRM_UI2_messageHTML( $classes, $msgHeader, $msgDetail, $ico, $id ); + + $zbs->pageMessages[] = $msg; + } +} - } +/* +====================================================== + / Parent Class for all Metabox + ====================================================== */ - $msgDetail = ''; - if (is_array($messages)) foreach ($messages as $message){ +/* +====================================================== + Global metabox helper funcs + ====================================================== */ - // < v3.0 - $messageStr = $message; +// ZBS splintered version of add_meta_box (wholly our own from now on, do not assume can be swapped out directly, may need integration) +// https://developer.wordpress.org/reference/functions/add_meta_box/ +function zeroBSCRM_add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null, $headless = false, $extraClasses = '', $capabilities = false ) { - // v3.0+ $message becomes a more thoughtful array - if (is_array($message)){ + // $id, $title, $callback,$headless + // echo 'zeroBSCRM_add_meta_box '.$id.':
'; print_r(array('head'=>$headless)); echo '
'; - // set this to stop php warnings if not got 'str' attr - $messageStr = $fallback; + global $zbs; - // retrieve - if (isset($message['str'])) $messageStr = $message['str']; + // simply maintains this array $zbs->metaboxes + // $zbs->metaboxes[] + + if ( empty( $screen ) ) { + $screen = get_current_screen(); + } elseif ( is_string( $screen ) ) { + // leave as is for zbs :) + $screen = convert_to_screen( $screen ); + } elseif ( is_array( $screen ) ) { + foreach ( $screen as $single_screen ) { + zeroBSCRM_add_meta_box( $id, $title, $callback, $single_screen, $context, $priority, $callback_args, $headless, $extraClasses, $capabilities ); + } + } - } + if ( ! isset( $screen->id ) ) { + return; + } - $msgDetail .= $messageStr.'
'; - } - - // genericified from DAL3.0 - $msg = zeroBSCRM_UI2_messageHTML($classes,$msgHeader,$msgDetail,$ico,$id); + $page = $screen->id; - $zbs->pageMessages[] = $msg; + if ( ! isset( $zbs->metaboxes ) ) { + $zbs->metaboxes = array(); + } + if ( ! isset( $zbs->metaboxes[ $page ] ) ) { + $zbs->metaboxes[ $page ] = array(); + } + if ( ! isset( $zbs->metaboxes[ $page ][ $context ] ) ) { + $zbs->metaboxes[ $page ][ $context ] = array(); + } - } - } + foreach ( array_keys( $zbs->metaboxes[ $page ] ) as $a_context ) { + foreach ( array( 'high', 'core', 'default', 'low' ) as $a_priority ) { + if ( ! isset( $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) ) { + continue; + } -/* ====================================================== - / Parent Class for all Metabox - ====================================================== */ + // If a core box was previously added or removed by a plugin, don't add. + if ( 'core' == $priority ) { + // If core box previously deleted, don't add + if ( false === $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) { + return; + } + + /* + * If box was added with default priority, give it core priority to + * maintain sort order. + */ + if ( 'default' == $a_priority ) { + $zbs->metaboxes[ $page ][ $a_context ]['core'][ $id ] = $zbs->metaboxes[ $page ][ $a_context ]['default'][ $id ]; + unset( $zbs->metaboxes[ $page ][ $a_context ]['default'][ $id ] ); + } + return; + } + // If no priority given and id already present, use existing priority. + if ( empty( $priority ) ) { + $priority = $a_priority; + /* + * Else, if we're adding to the sorted priority, we don't know the title + * or callback. Grab them from the previously added context/priority. + */ + } elseif ( 'sorted' == $priority ) { + $title = $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ]['title']; + $callback = $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ]['callback']; + $callback_args = $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ]['args']; + $headless = $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ]['headless']; + $extraClasses = $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ]['extraclasses']; + $capabilities = $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ]['capabilities']; + } + // An id can be in only one priority and one context. + if ( $priority != $a_priority || $context != $a_context ) { + unset( $zbs->metaboxes[ $page ][ $a_context ][ $a_priority ][ $id ] ); + } + } + } + if ( empty( $priority ) ) { + $priority = 'low'; + } + // default caps + if ( ! is_array( $capabilities ) ) { + $capabilities = array( + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal', 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved + ); + } -/* ====================================================== - Global metabox helper funcs - ====================================================== */ + if ( ! isset( $zbs->metaboxes[ $page ][ $context ][ $priority ] ) ) { + $zbs->metaboxes[ $page ][ $context ][ $priority ] = array(); + } -// ZBS splintered version of add_meta_box (wholly our own from now on, do not assume can be swapped out directly, may need integration) -// https://developer.wordpress.org/reference/functions/add_meta_box/ -function zeroBSCRM_add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null, $headless = false, $extraClasses = '', $capabilities=false) { - - // $id, $title, $callback,$headless - //echo 'zeroBSCRM_add_meta_box '.$id.':
'; print_r(array('head'=>$headless)); echo '
'; - - global $zbs; - - // simply maintains this array $zbs->metaboxes - //$zbs->metaboxes[] - - if ( empty( $screen ) ) { - $screen = get_current_screen(); - } elseif ( is_string( $screen ) ) { - // leave as is for zbs :) - $screen = convert_to_screen( $screen ); - } elseif ( is_array( $screen ) ) { - foreach ( $screen as $single_screen ) { - zeroBSCRM_add_meta_box( $id, $title, $callback, $single_screen, $context, $priority, $callback_args, $headless, $extraClasses, $capabilities ); - } - } - - if ( ! isset( $screen->id ) ) { - return; - } - - $page = $screen->id; - - if ( !isset($zbs->metaboxes) ) - $zbs->metaboxes = array(); - if ( !isset($zbs->metaboxes[$page]) ) - $zbs->metaboxes[$page] = array(); - if ( !isset($zbs->metaboxes[$page][$context]) ) - $zbs->metaboxes[$page][$context] = array(); - - foreach ( array_keys($zbs->metaboxes[$page]) as $a_context ) { - foreach ( array('high', 'core', 'default', 'low') as $a_priority ) { - if ( !isset($zbs->metaboxes[$page][$a_context][$a_priority][$id]) ) - continue; - - // If a core box was previously added or removed by a plugin, don't add. - if ( 'core' == $priority ) { - // If core box previously deleted, don't add - if ( false === $zbs->metaboxes[$page][$a_context][$a_priority][$id] ) - return; - - /* - * If box was added with default priority, give it core priority to - * maintain sort order. - */ - if ( 'default' == $a_priority ) { - $zbs->metaboxes[$page][$a_context]['core'][$id] = $zbs->metaboxes[$page][$a_context]['default'][$id]; - unset($zbs->metaboxes[$page][$a_context]['default'][$id]); - } - return; - } - // If no priority given and id already present, use existing priority. - if ( empty($priority) ) { - $priority = $a_priority; - /* - * Else, if we're adding to the sorted priority, we don't know the title - * or callback. Grab them from the previously added context/priority. - */ - } elseif ( 'sorted' == $priority ) { - $title = $zbs->metaboxes[$page][$a_context][$a_priority][$id]['title']; - $callback = $zbs->metaboxes[$page][$a_context][$a_priority][$id]['callback']; - $callback_args = $zbs->metaboxes[$page][$a_context][$a_priority][$id]['args']; - $headless = $zbs->metaboxes[$page][$a_context][$a_priority][$id]['headless']; - $extraClasses = $zbs->metaboxes[$page][$a_context][$a_priority][$id]['extraclasses']; - $capabilities = $zbs->metaboxes[$page][$a_context][$a_priority][$id]['capabilities']; - } - // An id can be in only one priority and one context. - if ( $priority != $a_priority || $context != $a_context ) - unset($zbs->metaboxes[$page][$a_context][$a_priority][$id]); - } - } - - if ( empty($priority) ) - $priority = 'low'; - - // default caps - if (!is_array($capabilities)) $capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('normal','side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved - - ); - - if ( !isset($zbs->metaboxes[$page][$context][$priority]) ) - $zbs->metaboxes[$page][$context][$priority] = array(); - - $zbs->metaboxes[$page][$context][$priority][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $callback_args, 'headless' => $headless, 'extraclasses' => $extraClasses, 'capabilities' => $capabilities); + $zbs->metaboxes[ $page ][ $context ][ $priority ][ $id ] = array( + 'id' => $id, + 'title' => $title, + 'callback' => $callback, + 'args' => $callback_args, + 'headless' => $headless, + 'extraclasses' => $extraClasses, + 'capabilities' => $capabilities, + ); } /** * Meta-Box template function (ZBS MODIFIED VER) @@ -399,493 +416,530 @@ function zeroBSCRM_add_meta_box( $id, $title, $callback, $screen = null, $contex * * @staticvar bool $already_sorted * - * @param string $screen - * @param string $context box context - * @param mixed $object gets passed to the box callback function as first parameter + * @param string $screen + * @param string $context box context + * @param mixed $object gets passed to the box callback function as first parameter * @return int number of meta_boxes */ function zeroBSCRM_do_meta_boxes( $screen, $context, $object ) { - global $zbs; - static $already_sorted = false; - - if ( empty( $screen ) ) - $screen = get_current_screen(); - elseif ( is_string( $screen ) ) - $screen = convert_to_screen( $screen ); - $page = $screen->id; - - // is this page a new edit: - global $zbsPage; - $isNewEdit = false; if (isset($zbsPage['new_edit'])) $isNewEdit = $zbsPage['new_edit']; //echo 'pre:
'.print_r($zbsPage,1).'
'; - - printf('
', esc_html($context)); - /* This was the previous wp organisation, which nearly worked for us, except we now want tab groups :) - $hidden = get_hidden_meta_boxes( $screen ); - // Grab the ones the user has manually sorted. Pull them out of their previous context/priority and into the one the user chose - if ( ! $already_sorted && $sorted = get_user_option( "meta-box-order_$page" ) ) { - foreach ( $sorted as $box_context => $ids ) { - foreach ( explode( ',', $ids ) as $id ) { - if ( $id && 'dashboard_browser_nag' !== $id ) { - zeroBSCRM_add_meta_box( $id, null, null, $screen, $box_context, 'sorted' ); - } - } - } - } - */ - - //echo 'Screen: '.$zbs->pageKey.' # '.$context; - // use ours - $screenOpts = $zbs->global_screen_options(); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $hidden = array(); if (is_array($screenOpts) && isset($screenOpts['mb_hidden']) && is_array($screenOpts['mb_hidden'])) $hidden = $screenOpts['mb_hidden']; - $minimised = array(); if (is_array($screenOpts) && isset($screenOpts['mb_mini']) && is_array($screenOpts['mb_mini'])) $minimised = $screenOpts['mb_mini']; + global $zbs; + static $already_sorted = false; + + if ( empty( $screen ) ) { + $screen = get_current_screen(); + } elseif ( is_string( $screen ) ) { + $screen = convert_to_screen( $screen ); + } + $page = $screen->id; - - // Basically here - // $zbs->metaboxes[ $page ][ $context ] = DEFAULTs - // $screenOptionsList = USER DESIRED ORDER - zeroBSCRM_applyScreenOptions($screenOpts,$page,$context); + // is this page a new edit: + global $zbsPage; + $isNewEdit = false; + if ( isset( $zbsPage['new_edit'] ) ) { + $isNewEdit = $zbsPage['new_edit']; // echo 'pre:
'.print_r($zbsPage,1).'
'; + } - $already_sorted = true; - $i = 0; - if ( isset( $zbs->metaboxes[ $page ][ $context ] ) ) { - foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) { - if ( isset( $zbs->metaboxes[ $page ][ $context ][ $priority ]) ) { - foreach ( (array) $zbs->metaboxes[ $page ][ $context ][ $priority ] as $boxID => $box ) { - if ( false == $box ) // || ! $box['title'] - continue; + printf( '
', esc_html( $context ) ); + /* + This was the previous wp organisation, which nearly worked for us, except we now want tab groups :) + $hidden = get_hidden_meta_boxes( $screen ); + // Grab the ones the user has manually sorted. Pull them out of their previous context/priority and into the one the user chose + if ( ! $already_sorted && $sorted = get_user_option( "meta-box-order_$page" ) ) { + foreach ( $sorted as $box_context => $ids ) { + foreach ( explode( ',', $ids ) as $id ) { + if ( $id && 'dashboard_browser_nag' !== $id ) { + zeroBSCRM_add_meta_box( $id, null, null, $screen, $box_context, 'sorted' ); + } + } + } + } + */ + + // echo 'Screen: '.$zbs->pageKey.' # '.$context; + // use ours + $screenOpts = $zbs->global_screen_options(); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $hidden = array(); + if ( is_array( $screenOpts ) && isset( $screenOpts['mb_hidden'] ) && is_array( $screenOpts['mb_hidden'] ) ) { + $hidden = $screenOpts['mb_hidden']; + } + $minimised = array(); + if ( is_array( $screenOpts ) && isset( $screenOpts['mb_mini'] ) && is_array( $screenOpts['mb_mini'] ) ) { + $minimised = $screenOpts['mb_mini']; + } - // hide_on_new (if this page is edit->new, and this metabox has hide_on_new - just don't load it.) - if ($isNewEdit && isset($box['capabilities']) && isset($box['capabilities']['hide_on_new']) && $box['capabilities']['hide_on_new']){ - continue; - } + // Basically here + // $zbs->metaboxes[ $page ][ $context ] = DEFAULTs + // $screenOptionsList = USER DESIRED ORDER + zeroBSCRM_applyScreenOptions( $screenOpts, $page, $context ); - $i++; + $already_sorted = true; + $i = 0; + if ( isset( $zbs->metaboxes[ $page ][ $context ] ) ) { + foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) { + if ( isset( $zbs->metaboxes[ $page ][ $context ][ $priority ] ) ) { + foreach ( (array) $zbs->metaboxes[ $page ][ $context ][ $priority ] as $boxID => $box ) { + if ( false == $box ) { // || ! $box['title'] + continue; + } - // if tab group - // https://semantic-ui.com/modules/tab.html#/examples - if (isset($box['istagroup'])){ + // hide_on_new (if this page is edit->new, and this metabox has hide_on_new - just don't load it.) + if ( $isNewEdit && isset( $box['capabilities'] ) && isset( $box['capabilities']['hide_on_new'] ) && $box['capabilities']['hide_on_new'] ) { + continue; + } - // this puts out header - zeroBSCRM_do_meta_box_htmlTabHead($boxID,$box); + ++$i; - // this puts out each as body to header - $indx = 0; - foreach ($box['boxes'] as $subbox){ + // if tab group + // https://semantic-ui.com/modules/tab.html#/examples + if ( isset( $box['istagroup'] ) ) { - // active tab - $isActive = false; if ($indx == 0) $isActive = true; + // this puts out header + zeroBSCRM_do_meta_box_htmlTabHead( $boxID, $box ); - // final html - simple normal out - zeroBSCRM_do_meta_box_html($subbox,$page,$hidden,$object,$minimised,true,$isActive); + // this puts out each as body to header + $indx = 0; + foreach ( $box['boxes'] as $subbox ) { - $indx++; + // active tab + $isActive = false; + if ( $indx == 0 ) { + $isActive = true; + } - } + // final html - simple normal out + zeroBSCRM_do_meta_box_html( $subbox, $page, $hidden, $object, $minimised, true, $isActive ); - } else { + ++$indx; - // final html - simple normal out - zeroBSCRM_do_meta_box_html($box,$page,$hidden,$object,$minimised); + } + } else { - } + // final html - simple normal out + zeroBSCRM_do_meta_box_html( $box, $page, $hidden, $object, $minimised ); - } - } - } - } - echo "
"; - return $i; + } + } + } + } + } + echo '
'; + return $i; } -function zeroBSCRM_applyScreenOptions($screenOpts = false,$page = '', $context = ''){ +function zeroBSCRM_applyScreenOptions( $screenOpts = false, $page = '', $context = '' ) { global $zbs; if ( ! is_array( $screenOpts ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $screenOpts = $zbs->global_screen_options(); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - $screenOptionsList = array(); if (is_array($screenOpts) && isset($screenOpts['mb_'.$context]) && is_array($screenOpts['mb_'.$context])) $screenOptionsList = $screenOpts['mb_'.$context]; - // not needed here: $hidden = array(); if (is_array($screenOpts) && isset($screenOpts['mb_hidden']) && is_array($screenOpts['mb_hidden'])) $hidden = $screenOpts['mb_hidden']; + $screenOptionsList = array(); + if ( is_array( $screenOpts ) && isset( $screenOpts[ 'mb_' . $context ] ) && is_array( $screenOpts[ 'mb_' . $context ] ) ) { + $screenOptionsList = $screenOpts[ 'mb_' . $context ]; + } + // not needed here: $hidden = array(); if (is_array($screenOpts) && isset($screenOpts['mb_hidden']) && is_array($screenOpts['mb_hidden'])) $hidden = $screenOpts['mb_hidden']; - // Basically here - // $zbs->metaboxes[ $page ][ $context ] = DEFAULTs - // $screenOptionsList = USER DESIRED ORDER + // Basically here + // $zbs->metaboxes[ $page ][ $context ] = DEFAULTs + // $screenOptionsList = USER DESIRED ORDER - // if default + screenoptions order: - if ( isset( $zbs->metaboxes[ $page ][ $context ] ) && isset($screenOptionsList) && is_array($screenOptionsList) && count($screenOptionsList) > 0 ) { + // if default + screenoptions order: + if ( isset( $zbs->metaboxes[ $page ][ $context ] ) && isset( $screenOptionsList ) && is_array( $screenOptionsList ) && count( $screenOptionsList ) > 0 ) { - // DEBUG echo '

Global

'; print_r($zbs->metaboxes[ $page ][ $context ]); echo '
'; - // DEBUG echo '

User

'; print_r($screenOptionsList); echo '
'; + // DEBUG echo '

Global

'; print_r($zbs->metaboxes[ $page ][ $context ]); echo '
'; + // DEBUG echo '

User

'; print_r($screenOptionsList); echo '
'; - // so here we merge the two into a MEGA list :) - $metaboxes = $zbs->metaboxes[ $page ][ $context ]; //array('high'=>array(), 'sorted'=>array(), 'core'=>array(), 'default'=>array(), 'low'=>array()); - $soMetaboxes = array(); + // so here we merge the two into a MEGA list :) + $metaboxes = $zbs->metaboxes[ $page ][ $context ]; // array('high'=>array(), 'sorted'=>array(), 'core'=>array(), 'default'=>array(), 'low'=>array()); + $soMetaboxes = array(); - // for the sake of our metaboxes + simplicity - // for now we'll only use to priority slots 'high','low' - // ... leaving the others in place. - // So: - // - No screen options = load as normal, based on wp priorities (as added in metabox init) - // - Screen options = load these in order user has saved (all under 'high') - // ... when there is a new metabox added by us (so not in 'screenoptions') this is added either 'high' or 'low' - // ... always at the end of whatever priority it is given in its metabox init :) + // for the sake of our metaboxes + simplicity + // for now we'll only use to priority slots 'high','low' + // ... leaving the others in place. + // So: + // - No screen options = load as normal, based on wp priorities (as added in metabox init) + // - Screen options = load these in order user has saved (all under 'high') + // ... when there is a new metabox added by us (so not in 'screenoptions') this is added either 'high' or 'low' + // ... always at the end of whatever priority it is given in its metabox init :) - foreach ($screenOptionsList as $metaboxID => $metaboxVal){ + foreach ( $screenOptionsList as $metaboxID => $metaboxVal ) { - // these'll be in priority order - // ... so we PICK them out of wherever they are, and add them to wherever they need to be - // but because we just store the ID in the screenopts we have to do a bit of a dance.. + // these'll be in priority order + // ... so we PICK them out of wherever they are, and add them to wherever they need to be + // but because we just store the ID in the screenopts we have to do a bit of a dance.. - // NOTE this also has to catch TABS which are csv's of mb id's - // here we check if tab - $tabgroup = false; - if ($metaboxVal != 'self'){ + // NOTE this also has to catch TABS which are csv's of mb id's + // here we check if tab + $tabgroup = false; + if ( $metaboxVal != 'self' ) { - // is tab section - $mbIDsToAdd = explode(',', $metaboxVal); - $tabgroup = true; + // is tab section + $mbIDsToAdd = explode( ',', $metaboxVal ); + $tabgroup = true; - } else { + } else { - // only one - $mbIDsToAdd = array($metaboxID); + // only one + $mbIDsToAdd = array( $metaboxID ); - } + } - // then we cycle through each (provided) id - foreach ($mbIDsToAdd as $mbIDToAdd){ + // then we cycle through each (provided) id + foreach ( $mbIDsToAdd as $mbIDToAdd ) { - // first we find it in existing arrs - $existingMB = false; - $fromPriority = false; + // first we find it in existing arrs + $existingMB = false; + $fromPriority = false; - // through each prioty - foreach ($metaboxes as $priority => $metaboxArr){ + // through each prioty + foreach ( $metaboxes as $priority => $metaboxArr ) { - // log source - $fromPriority = $priority; + // log source + $fromPriority = $priority; - // through each mb - foreach ($metaboxArr as $mbID => $mb){ + // through each mb + foreach ( $metaboxArr as $mbID => $mb ) { - // found it - if ($mbIDToAdd == $mbID){ + // found it + if ( $mbIDToAdd == $mbID ) { - // grab item - $existingMB = $mb; - break 2; + // grab item + $existingMB = $mb; + break 2; - } + } + } + } - } + // if found it + if ( $existingMB !== false ) { - } + // remove it from current place + unset( $metaboxes[ $fromPriority ][ $mbIDToAdd ] ); - // if found it - if ($existingMB !== false){ + if ( $tabgroup ) { - // remove it from current place - unset($metaboxes[$fromPriority][$mbIDToAdd]); + // set if not set + if ( ! isset( $soMetaboxes[ $metaboxID ] ) ) { + $soMetaboxes[ $metaboxID ] = array(); + } + if ( ! isset( $soMetaboxes[ $metaboxID ]['boxes'] ) ) { + $soMetaboxes[ $metaboxID ]['boxes'] = array(); + } - if ($tabgroup){ + // add to our pile (of piles) + $soMetaboxes[ $metaboxID ]['boxes'][ $mbIDToAdd ] = $existingMB; - // set if not set - if (!isset($soMetaboxes[$metaboxID])) $soMetaboxes[$metaboxID] = array(); - if (!isset($soMetaboxes[$metaboxID]['boxes'])) $soMetaboxes[$metaboxID]['boxes'] = array(); + // make sure this flag is set + $soMetaboxes[ $metaboxID ]['istagroup'] = true; - // add to our pile (of piles) - $soMetaboxes[$metaboxID]['boxes'][$mbIDToAdd] = $existingMB; + } else { - // make sure this flag is set - $soMetaboxes[$metaboxID]['istagroup'] = true; + // add to our pile + $soMetaboxes[ $metaboxID ] = $existingMB; + } + } + } // each mb id (1 or tabs multi) - } else { + } - // add to our pile - $soMetaboxes[$metaboxID] = $existingMB; + // now if we have any in our pile, we shoehorn them in at the top of high (for now) + // so... when we add a new metabox (That people wont have saved in their screen opts) + // ... it'll do this: + // if priority = high - add to TOP + // if priority != high - add at bottom + if ( count( $soMetaboxes ) > 0 ) { + + $newHighPriority = array(); + + // first clone in any in from other high priority array + // (this'll catch where we've added new metaboxes that the user doesn't have in their screen opts) + if ( isset( $metaboxes['high'] ) && is_array( $metaboxes['high'] ) && count( $metaboxes['high'] ) > 0 ) { + foreach ( $metaboxes['high'] as $mbID => $mb ) { + if ( ! in_array( $mbID, array_keys( $soMetaboxes ) ) ) { + $newHighPriority[ $mbID ] = $mb; + } + } + } - } + // add ours :) + $newHighPriority = array_merge( $newHighPriority, $soMetaboxes ); + + // add any in from other priority arrays + // (this'll catch where we've added new metaboxes that the user doesn't have in their screen opts) + foreach ( array( 'sorted', 'core', 'default', 'low' ) as $priority ) { + if ( isset( $metaboxes[ $priority ] ) && count( $metaboxes[ $priority ] ) > 0 ) { + foreach ( $metaboxes[ $priority ] as $mbID => $mb ) { + if ( ! in_array( $mbID, array_keys( $soMetaboxes ) ) ) { + $newHighPriority[ $mbID ] = $mb; + } + } + } + } + // then overwrite it! (effectively for ) + // actually needs to be totally overwritten $metaboxes['high'] = $newHighPriority; + $zbs->metaboxes[ $page ][ $context ] = array( 'high' => $newHighPriority ); - } + // and clean up + unset( $newHighPriority, $soMetaboxes, $metaboxes ); - } // each mb id (1 or tabs multi) + } + } +} - } +// https://semantic-ui.com/modules/tab.html#/examples +function zeroBSCRM_do_meta_box_htmlTabHead( $tabsID = '', $tabs = false ) { - // now if we have any in our pile, we shoehorn them in at the top of high (for now) - // so... when we add a new metabox (That people wont have saved in their screen opts) - // ... it'll do this: - // if priority = high - add to TOP - // if priority != high - add at bottom - if (count($soMetaboxes) > 0){ + if ( $tabs !== false ) { - $newHighPriority = array(); + // echo '

'.$tabsID.'

';print_r($tabs); echo '
'; - // first clone in any in from other high priority array - // (this'll catch where we've added new metaboxes that the user doesn't have in their screen opts) - if (isset($metaboxes['high']) && is_array($metaboxes['high']) && count($metaboxes['high']) > 0) foreach ($metaboxes['high'] as $mbID => $mb){ - if (!in_array($mbID,array_keys($soMetaboxes))) $newHighPriority[$mbID] = $mb; - } + echo ''; - } + } } -//https://semantic-ui.com/modules/tab.html#/examples -function zeroBSCRM_do_meta_box_htmlTabHead($tabsID='',$tabs=false){ - - if ($tabs !== false){ - - //echo '

'.$tabsID.'

';print_r($tabs); echo '
'; - - echo ''; + $dataAttrStr .= 'data-' . str_replace( '_', '-', $capKey ) . '="' . $capVStr . '"'; + } + } + // classes + $classes = 'zbs-metabox'; + $extraAttrs = ''; - } + // hidden class + $classes .= in_array( $box['id'], $hidden ) ? ' hide-if-js zbs-hidden' : ''; -} + // minimised class + $classes .= in_array( $box['id'], $minimised ) ? ' zbs-minimised' : ''; + // static class + $classes .= $canMove ? '' : ' zbs-static'; -function zeroBSCRM_do_meta_box_html($box,$page,$hidden,$object,$minimised,$isTabPane=false,$isActiveTab=false){ - - /* HTML adapted to suit semantic, from this, the previous wp code: - $hidden_class = in_array($box['id'], $hidden) ? ' hide-if-js' : ''; - echo '
' . "\n"; - if ( 'dashboard_browser_nag' != $box['id'] ) { - $widget_title = $box[ 'title' ]; - if ( is_array( $box[ 'args' ] ) && isset( $box[ 'args' ][ '__widget_basename' ] ) ) { - $widget_title = $box[ 'args' ][ '__widget_basename' ]; - // Do not pass this parameter to the user callback function. - unset( $box[ 'args' ][ '__widget_basename' ] ); - } - echo ''; - } - echo "

{$box['title']}

\n"; - echo '
' . "\n"; - call_user_func($box['callback'], $object, $box); - echo "
\n"; - echo "
\n"; - */ - - $htmlClasses = 'ui segment'; - - // headless? - $headless = false; if (isset($box['headless']) && $box['headless']) $headless = true; - - // extra classes - $extraClasses = ''; if (isset($box['extraclasses']) && $box['extraclasses']) $extraClasses = $box['extraclasses']; - - // convert capabilites into data-atr - // these get added to headed meta only... - // Also set vars here e.g. canMinimise - $dataAttrStr = ''; $canMinimise = false; $canHide = false; $canMove = false; - if (isset($box['capabilities']) && is_array($box['capabilities'])){ + // if is a tab pane... + // class="ui bottom attached tab segment active" data-tab="first" + if ( $isTabPane ) { + $classes .= ' ui bottom attached tab segment'; + if ( $isActiveTab ) { + $classes .= ' active'; + } + $extraAttrs .= ' data-tab="' . $box['id'] . '"'; - if (isset($box['capabilities']['can_minimise']) && $box['capabilities']['can_minimise']) $canMinimise = true; - if (isset($box['capabilities']['can_hide']) && $box['capabilities']['can_hide']) $canHide = true; - if (isset($box['capabilities']['can_move']) && $box['capabilities']['can_move']) $canMove = true; - - - foreach ($box['capabilities'] as $capKey => $capVal){ - if (!empty($dataAttrStr)) $dataAttrStr .= ' '; - - // arrays get csv'd - $capVStr = ''; - if (is_array($capVal)) - $capVStr = implode(',', $capVal); - else - $capVStr = $capVal; - - $dataAttrStr .= 'data-'.str_replace('_','-',$capKey).'="'.$capVStr.'"'; - } - - } - - // classes - $classes = 'zbs-metabox'; $extraAttrs = ''; - - // hidden class - $classes .= in_array($box['id'], $hidden) ? ' hide-if-js zbs-hidden' : ''; - - // minimised class - $classes .= in_array($box['id'], $minimised) ? ' zbs-minimised' : ''; - - // static class - $classes .= $canMove ? '' : ' zbs-static'; - - // if is a tab pane... - // class="ui bottom attached tab segment active" data-tab="first" - if ($isTabPane) { - $classes .= ' ui bottom attached tab segment'; - if ($isActiveTab) $classes .= ' active'; - $extraAttrs .= ' data-tab="'.$box['id'].'"'; - - // always - $canMinimise = false; - $headless = true; - $htmlClasses = ''; - } - - - echo '
'; - - - // hide/minimise option - $hideMinimiseMenu = ''; - if ($canMinimise){ - - // minimise - - // now inc both carets, class presence turns on/off - $hideMinimiseMenu = '
'; - - } - - if (!$headless){ - echo ''; - foreach ( array( 'normal', 'side' ) as $context ) { + $htmlClasses .= ' bottom attached'; + } + echo '
' . "\n"; // $hidden_class. + call_user_func( $box['callback'], $object, $box ); + echo '
'; // /.zbs-metabox-body + echo '
' . $box['title'] . '
'; // this is BLOCKER for drag-drop support -// + echo "
\n"; +} - foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) { +// retrieves metabox list for current page (all contexts) +// does so without priorities (e.g. high,low) +function zeroBSCRM_getCurrentMetaboxesFlatArr() { - if (isset($mbWithPriorities[$context]) && isset($mbWithPriorities[$context][$priority]) && is_array($mbWithPriorities[$context][$priority])){ + $mb = array( + 'normal' => array(), + 'side' => array(), + ); + $mbWithPriorities = zeroBSCRM_getCurrentMetaboxes(); - $mb[$context] = array_merge($mb[$context],$mbWithPriorities[$context][$priority]); - } + if ( is_array( $mbWithPriorities ) ) { - } - } + foreach ( array( 'normal', 'side' ) as $context ) { - } + foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) { + if ( isset( $mbWithPriorities[ $context ] ) && isset( $mbWithPriorities[ $context ][ $priority ] ) && is_array( $mbWithPriorities[ $context ][ $priority ] ) ) { - return $mb; + $mb[ $context ] = array_merge( $mb[ $context ], $mbWithPriorities[ $context ][ $priority ] ); + } + } + } + } + return $mb; } // retrieves metabox list for current page (all contexts) -function zeroBSCRM_getCurrentMetaboxes(){ +function zeroBSCRM_getCurrentMetaboxes() { - global $zbs; - - $metaboxes = array(); - $pageKey = $zbs->pageKey; - - // cycle through context/[priority] - foreach ( array( 'normal', 'side' ) as $context ) { + global $zbs; - $mb = zeroBSCRM_getMetaboxes($pageKey,$context); - //echo 'pagekey:'.$pageKey.'+'.$context.'
'; print_r($mb); echo '
'; + $metaboxes = array(); + $pageKey = $zbs->pageKey; - if (is_array($mb) && count($mb) > 0) $metaboxes[$context] = $mb; + // cycle through context/[priority] + foreach ( array( 'normal', 'side' ) as $context ) { - } + $mb = zeroBSCRM_getMetaboxes( $pageKey, $context ); + // echo 'pagekey:'.$pageKey.'+'.$context.'
'; print_r($mb); echo '
'; - return $metaboxes; + if ( is_array( $mb ) && count( $mb ) > 0 ) { + $metaboxes[ $context ] = $mb; + } + } + return $metaboxes; } // retrieves metabox list for a page + context // (NOTE: Does not sort by user screen options) -function zeroBSCRM_getMetaboxes($page='',$context=''){ - - global $zbs; +function zeroBSCRM_getMetaboxes( $page = '', $context = '' ) { - if (isset($zbs->metaboxes[ $page ]) && isset($zbs->metaboxes[ $page ][ $context ])) return $zbs->metaboxes[ $page ][ $context ]; + global $zbs; - return array(); + if ( isset( $zbs->metaboxes[ $page ] ) && isset( $zbs->metaboxes[ $page ][ $context ] ) ) { + return $zbs->metaboxes[ $page ][ $context ]; + } + return array(); } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes.SubmitBoxes.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes.SubmitBoxes.php index 8709629e3db6..772a4d5e8323 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes.SubmitBoxes.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes.SubmitBoxes.php @@ -1,5 +1,5 @@ -instance instanceof wProject_Metabox ) { - # wp_die( sprintf( __( 'Cannot instantiate singleton class: %1$s. Use %1$s::$instance instead.', 'zero-bs-crm' ), __CLASS__ ) ); - #} else { - self::$instance = $this; - #} - - - #$this->postType = 'zerobs_customer'; - #add_action( 'add_meta_boxes', array( $this, 'create_meta_box' ) ); - #} Moved to multiples 1.1.19 WH - - $this->postTypes = array('zerobs_invoice'); - #} Temp - $this->postTypesLabels = array( - 'zerobs_invoice' => 'Invoice' - ); - add_action( 'add_meta_boxes', array( $this, 'initMetaBox' ) ); - - #add_filter( 'save_post', array( $this, 'save_meta_box' ), 10, 2 ); - } - - public function initMetaBox(){ - - if (count($this->postTypes) > 0) foreach ($this->postTypes as $pt){ - - #} pass an arr - $callBackArr = array($this,$pt); - - add_meta_box( - 'wpzbscsub_itemdetails_'.$pt, - __($this->postTypesLabels[$pt],"zero-bs-crm") .' Actions', #quick title - array( $this, 'print_meta_box' ), - $pt, - 'side', - 'low', - $callBackArr - ); - - } - - } - /* - public function create_meta_box() { - - - #} Don't share for new customers :) - #if (isset($this->ID)){ - - add_meta_box( - 'wpzbscext_itemdetails', - 'External Source(s)', - array( $this, 'print_meta_box' ), - $this->postType, - 'side', - 'low' - ); - - #} - } - */ - public function print_meta_box( $post, $metabox ) { - - #} Post type - $postType = ''; if (isset($metabox['args']) && isset($metabox['args'][1]) && !empty($metabox['args'][1])) $postType = $metabox['args'][1]; - - #} Only load if is legit. - if (in_array($postType,array('zerobs_invoice'))){ - - #} if a saved post... - if (isset($post->post_status) && $post->post_status != "auto-draft"){ - ?> - - - - ID,'zbs_customer_invoice_meta', true); - - if(!isset($zbs_inv_meta['status'])){ - $zbs_stat = 'Draft'; - }else{ - $zbs_stat = $zbs_inv_meta['status']; - } - - global $zbsCustomerInvoiceFields; - - $sel=''; - ?> -
-
-
- -
-
- -
-
-
- - - - - -
- - - -
- - -
- -
- ID ) ) { - if ( !EMPTY_TRASH_DAYS ) - $delete_text = __('Delete Permanently', "zero-bs-crm"); - else - $delete_text = __('Move to Trash', "zero-bs-crm"); - ?> - -
-
-
- - - - - - - post_type == $this->postType){ - - #} Nothing needed - } - } - - return $post; - } */ - } +/* +====================================================== + Init Func + ====================================================== */ + +function zeroBSCRM_SubmitMetaboxSetup() { + + $zeroBS__SubmitMetabox = new zeroBS__SubmitMetabox( __FILE__ ); +} + + add_action( 'admin_init', 'zeroBSCRM_SubmitMetaboxSetup' ); + +/* +====================================================== + / Init Func + ====================================================== */ + +/* +====================================================== + Submit Metabox + ====================================================== */ + +class zeroBS__SubmitMetabox { + + static $instance; + #private $packPerm; + #private $pack; + private $postTypes; + private $postTypesLabels; + + public function __construct( $plugin_file ) { + # if ( $this->instance instanceof wProject_Metabox ) { + # wp_die( sprintf( __( 'Cannot instantiate singleton class: %1$s. Use %1$s::$instance instead.', 'zero-bs-crm' ), __CLASS__ ) ); + #} else { + self::$instance = $this; + #} + + #$this->postType = 'zerobs_customer'; + #add_action( 'add_meta_boxes', array( $this, 'create_meta_box' ) ); + #} Moved to multiples 1.1.19 WH + + $this->postTypes = array( 'zerobs_invoice' ); + #} Temp + $this->postTypesLabels = array( + 'zerobs_invoice' => 'Invoice', + ); + add_action( 'add_meta_boxes', array( $this, 'initMetaBox' ) ); + + #add_filter( 'save_post', array( $this, 'save_meta_box' ), 10, 2 ); + } + + public function initMetaBox() { + + if ( count( $this->postTypes ) > 0 ) { + foreach ( $this->postTypes as $pt ) { + + #} pass an arr + $callBackArr = array( $this, $pt ); + + add_meta_box( + 'wpzbscsub_itemdetails_' . $pt, + __( $this->postTypesLabels[ $pt ], 'zero-bs-crm' ) . ' Actions', #quick title + array( $this, 'print_meta_box' ), + $pt, + 'side', + 'low', + $callBackArr + ); + + } + } + } + /* + public function create_meta_box() { + + + #} Don't share for new customers :) + #if (isset($this->ID)){ + + add_meta_box( + 'wpzbscext_itemdetails', + 'External Source(s)', + array( $this, 'print_meta_box' ), + $this->postType, + 'side', + 'low' + ); + + #} + } + */ + public function print_meta_box( $post, $metabox ) { + + #} Post type + $postType = ''; + if ( isset( $metabox['args'] ) && isset( $metabox['args'][1] ) && ! empty( $metabox['args'][1] ) ) { + $postType = $metabox['args'][1]; + } + + #} Only load if is legit. + if ( in_array( $postType, array( 'zerobs_invoice' ) ) ) { + + #} if a saved post... + if ( isset( $post->post_status ) && $post->post_status != 'auto-draft' ) { + ?> + + + + ID, 'zbs_customer_invoice_meta', true ); + + if ( ! isset( $zbs_inv_meta['status'] ) ) { + $zbs_stat = 'Draft'; + } else { + $zbs_stat = $zbs_inv_meta['status']; + } + + global $zbsCustomerInvoiceFields; + + $sel = ''; + ?> +
+
+
+ +
+
+ +
+
+
+ + + + + +
+ + + +
+ + +
+ + +
+ ID ) ) { + if ( ! EMPTY_TRASH_DAYS ) { + $delete_text = __( 'Delete Permanently', 'zero-bs-crm' ); + } else { + $delete_text = __( 'Move to Trash', 'zero-bs-crm' ); + } + ?> + + +
+
+
+ + + + + + + post_type == $this->postType){ + + #} Nothing needed + } + } + + return $post; + } */ +} /** * End of Submit Metabox diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Companies.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Companies.php index ef41b3810663..922e8b07ce55 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Companies.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Companies.php @@ -1,5 +1,5 @@ -coOrgLabel = jpcrm_label_company(); - - // set these - $this->objType = 'company'; - $this->metaboxID = 'zerobs-company-edit'; - $this->metaboxTitle = $this->coOrgLabel.' '.__('Details','zero-bs-crm'); - $this->metaboxScreen = 'zbs-add-edit-company-edit'; - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved - - ); - - // call this - $this->initMetabox(); - - } - - public function html( $company, $metabox ) { - - global $zbs; - - // localise ID - $companyID = -1; if (is_array($company) && isset($company['id'])) $companyID = (int)$company['id']; - - // PerfTest: zeroBSCRM_performanceTest_startTimer('custmetabox-dataget'); - - #} Rather than reload all the time :) - global $zbsCompanyEditing; - - if (!isset($zbsCompanyEditing)){ - $zbsCompany = zeroBS_getCompany($companyID,false); - $zbsCompanyEditing = $zbsCompany; - } else { - $zbsCompany = $zbsCompanyEditing; - } - - global $zbsCompanyFields; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $fields = $zbsCompanyFields; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $show_id = (int) $zbs->settings->get( 'showid' ); - $fields_to_hide = $zbs->settings->get( 'fieldhides' ); - $show_addresses = (int) $zbs->settings->get( 'showaddress' ); - $show_second_address = (int) $zbs->settings->get( 'secondaddress' ); - $show_country_fields = $zbs->settings->get( 'countries' ); - $second_address_label = $zbs->settings->get( 'secondaddresslabel' ); - if ( empty( $second_address_label ) ) { - $second_address_label = __( 'Second Address', 'zero-bs-crm' ); - } - ?> - - - '; + #} Ownership + if ( zeroBSCRM_getSetting( 'perusercustomers' ) == '1' ) { + $zeroBS__CoMetabox_Ownership = new zeroBS__Metabox_Ownership( __FILE__, ZBS_TYPE_COMPANY ); + } +} - ?> + add_action( 'admin_init', 'zeroBSCRM_CompaniesMetaboxSetup' ); + +/* +====================================================== + / Init Func + ====================================================== */ + +/* +====================================================== + Company Metabox + ====================================================== */ + +class zeroBS__Metabox_Company extends zeroBS__Metabox { + + // this is for catching 'new' companys + private $newRecordNeedsRedir = false; + + private $coOrgLabel = ''; + + public function __construct( $plugin_file ) { + + // oldschool. + $this->coOrgLabel = jpcrm_label_company(); + + // set these + $this->objType = 'company'; + $this->metaboxID = 'zerobs-company-edit'; + $this->metaboxTitle = $this->coOrgLabel . ' ' . __( 'Details', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-company-edit'; + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( + + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved + + ); + + // call this + $this->initMetabox(); + } + + public function html( $company, $metabox ) { + + global $zbs; + + // localise ID + $companyID = -1; + if ( is_array( $company ) && isset( $company['id'] ) ) { + $companyID = (int) $company['id']; + } + + // PerfTest: zeroBSCRM_performanceTest_startTimer('custmetabox-dataget'); + + #} Rather than reload all the time :) + global $zbsCompanyEditing; + + if ( ! isset( $zbsCompanyEditing ) ) { + $zbsCompany = zeroBS_getCompany( $companyID, false ); + $zbsCompanyEditing = $zbsCompany; + } else { + $zbsCompany = $zbsCompanyEditing; + } + + global $zbsCompanyFields; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $fields = $zbsCompanyFields; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $show_id = (int) $zbs->settings->get( 'showid' ); + $fields_to_hide = $zbs->settings->get( 'fieldhides' ); + $show_addresses = (int) $zbs->settings->get( 'showaddress' ); + $show_second_address = (int) $zbs->settings->get( 'secondaddress' ); + $show_country_fields = $zbs->settings->get( 'countries' ); + $second_address_label = $zbs->settings->get( 'secondaddresslabel' ); + if ( empty( $second_address_label ) ) { + $second_address_label = __( 'Second Address', 'zero-bs-crm' ); + } + ?> + + + '; + } + + ?>
- 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>
- + #
- + - '; - define('ZBS_CO_SAVED',1); + + '; + define( 'ZBS_CO_SAVED', 1 ); - // no go. - $this->updateEmailDupeMessage($potentialID); + // DAL3.0+ + global $zbs; - // unset email change (leave as was) - $dataArr['email'] = zeroBS_companyEmail($company_id); + // check this + if ( empty( $company_id ) || $company_id < 1 ) { + $company_id = -1; + } - } + // retrieve data in format + // ... by using zeroBS_buildCompanyMeta, custom fields are 'dealt with' automatically + $dataArr = zeroBS_buildCompanyMeta( $_POST ); - } + // Use the tag-class function to retrieve any tags so we can add inline. + // Save tags against objid + $dataArr['tags'] = zeroBSCRM_tags_retrieveFromPostBag( true, ZBS_TYPE_COMPANY ); - #AVATARSAVE - save any avatar change if changed :) - if (isset($_POST['zbs-company-avatar-custom-url']) && !empty($_POST['zbs-company-avatar-custom-url'])) $dataArr['avatar'] = sanitize_text_field( $_POST['zbs-company-avatar-custom-url'] ); + // owner - saved here now, rather than ownership box, to allow for pre-hook update. (as tags) + $owner = -1; if ( isset( $_POST['zerobscrm-owner'] ) ) { - // Stripslashes - // This avoids us adding `O\'toole ltd' into the db. see #1107 - // ...this is more sensitive than using zeroBSCRM_stripSlashesFromArr - // in the long term it may make more sense to stripslashes pre insert/update in the DAL - // in the case of companies, there are no core fields which will be broken by stripslashes at this time (4.0.11) - $data_array = $dataArr; - foreach ($dataArr as $key => $val){ + // should this have perms check to see if user can actually assign to? or should that be DAL? + $potentialOwner = (int) sanitize_text_field( $_POST['zerobscrm-owner'] ); + if ( $potentialOwner > 0 ) { + $owner = $potentialOwner; + } + } - // op strings - $value = $val; - if ( is_string( $value ) ) $value = stripslashes( $value ); - - // pass into final array - $data_array[$key] = $value; + // now we check whether a user with this email already exists (separate to this company id), so we can warn them + // ... that it wont have changed the email + if ( isset( $dataArr['email'] ) && ! empty( $dataArr['email'] ) ) { - } + $potentialID = zeroBS_getCompanyIDWithEmail( $dataArr['email'] ); - // add update directly - $addUpdateReturn = $zbs->DAL->companies->addUpdateCompany(array( + if ( ! empty( $potentialID ) && $potentialID != $company_id ) { - 'id' => $company_id, - 'owner' => $owner, - 'data' => $data_array, - 'limitedFields' => -1, + // no go. + $this->updateEmailDupeMessage( $potentialID ); - )); + // unset email change (leave as was) + $dataArr['email'] = zeroBS_companyEmail( $company_id ); - // Note: For NEW contacts, we make sure a global is set here, that other update funcs can catch - // ... so it's essential this one runs first! - // this is managed in the metabox Class :) - if ($company_id == -1 && !empty($addUpdateReturn) && $addUpdateReturn != -1) { - - $company_id = $addUpdateReturn; - global $zbsJustInsertedMetaboxID; $zbsJustInsertedMetaboxID = $company_id; + } + } - // set this so it redirs - $this->newRecordNeedsRedir = true; - } + #AVATARSAVE - save any avatar change if changed :) + if ( isset( $_POST['zbs-company-avatar-custom-url'] ) && ! empty( $_POST['zbs-company-avatar-custom-url'] ) ) { + $dataArr['avatar'] = sanitize_text_field( $_POST['zbs-company-avatar-custom-url'] ); + } - // success? - if ($addUpdateReturn != -1 && $addUpdateReturn > 0){ + // Stripslashes + // This avoids us adding `O\'toole ltd' into the db. see #1107 + // ...this is more sensitive than using zeroBSCRM_stripSlashesFromArr + // in the long term it may make more sense to stripslashes pre insert/update in the DAL + // in the case of companies, there are no core fields which will be broken by stripslashes at this time (4.0.11) + $data_array = $dataArr; + foreach ( $dataArr as $key => $val ) { - // Update Msg - // this adds an update message which'll go out ahead of any content - // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); - // This adds to edit page - $this->updateMessage( $this->newRecordNeedsRedir ); + // op strings + $value = $val; + if ( is_string( $value ) ) { + $value = stripslashes( $value ); + } - // catch any non-critical messages - $nonCriticalMessages = $zbs->DAL->getErrors(ZBS_TYPE_COMPANY); - if (is_array($nonCriticalMessages) && count($nonCriticalMessages) > 0) $this->dalNoticeMessage($nonCriticalMessages); + // pass into final array + $data_array[ $key ] = $value; - } else { + } - // fail somehow - $failMessages = $zbs->DAL->getErrors(ZBS_TYPE_COMPANY); + // add update directly + $addUpdateReturn = $zbs->DAL->companies->addUpdateCompany( + array( - // show msg (retrieved from DAL err stack) - if (is_array($failMessages) && count($failMessages) > 0) - $this->dalErrorMessage($failMessages); - else - $this->dalErrorMessage(array(__('Insert/Update Failed with general error','zero-bs-crm'))); + 'id' => $company_id, + 'owner' => $owner, + 'data' => $data_array, + 'limitedFields' => -1, - // pass the pre-fill: - global $zbsObjDataPrefill; $zbsObjDataPrefill = $dataArr; + ) + ); - - } + // Note: For NEW contacts, we make sure a global is set here, that other update funcs can catch + // ... so it's essential this one runs first! + // this is managed in the metabox Class :) + if ( $company_id == -1 && ! empty( $addUpdateReturn ) && $addUpdateReturn != -1 ) { - } + $company_id = $addUpdateReturn; + global $zbsJustInsertedMetaboxID; + $zbsJustInsertedMetaboxID = $company_id; - return $company; - } + // set this so it redirs + $this->newRecordNeedsRedir = true; + } - // This catches 'new' contacts + redirs to right url - public function post_save_data($objID,$obj){ + // success? + if ( $addUpdateReturn != -1 && $addUpdateReturn > 0 ) { - if ($this->newRecordNeedsRedir){ + // Update Msg + // this adds an update message which'll go out ahead of any content + // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); + // This adds to edit page + $this->updateMessage( $this->newRecordNeedsRedir ); - global $zbs, $zbsJustInsertedMetaboxID; - if (!empty($zbsJustInsertedMetaboxID) && $zbsJustInsertedMetaboxID > 0){ + // catch any non-critical messages + $nonCriticalMessages = $zbs->DAL->getErrors( ZBS_TYPE_COMPANY ); + if ( is_array( $nonCriticalMessages ) && count( $nonCriticalMessages ) > 0 ) { + $this->dalNoticeMessage( $nonCriticalMessages ); + } + } else { - // redir - $zbs->new_record_edit_redirect( $this->objType, $zbsJustInsertedMetaboxID ); + // fail somehow + $failMessages = $zbs->DAL->getErrors( ZBS_TYPE_COMPANY ); - } + // show msg (retrieved from DAL err stack) + if ( is_array( $failMessages ) && count( $failMessages ) > 0 ) { + $this->dalErrorMessage( $failMessages ); + } else { + $this->dalErrorMessage( array( __( 'Insert/Update Failed with general error', 'zero-bs-crm' ) ) ); + } - } + // pass the pre-fill: + global $zbsObjDataPrefill; + $zbsObjDataPrefill = $dataArr; - } + } + } - public function updateMessage( $created = false ) { - $message = $this->coOrgLabel . ' ' . ( $created ? __( 'Created', 'zero-bs-crm' ) : __( 'Updated', 'zero-bs-crm' ) ); - // zbs-not-urgent means it'll auto hide after 1.5s - $msg = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent', $message,'','address book outline','companyUpdated'); + return $company; + } - // quick + dirty - global $zbs; + // This catches 'new' contacts + redirs to right url + public function post_save_data( $objID, $obj ) { - $zbs->pageMessages[] = $msg; + if ( $this->newRecordNeedsRedir ) { - } + global $zbs, $zbsJustInsertedMetaboxID; + if ( ! empty( $zbsJustInsertedMetaboxID ) && $zbsJustInsertedMetaboxID > 0 ) { - public function updateEmailDupeMessage($otherCompanyID=-1){ + // redir + $zbs->new_record_edit_redirect( $this->objType, $zbsJustInsertedMetaboxID ); - global $zbs; + } + } + } - $viewHTML = ' '.__('View','zero-bs-crm').' '.$this->coOrgLabel.''; + public function updateMessage( $created = false ) { + $message = $this->coOrgLabel . ' ' . ( $created ? __( 'Created', 'zero-bs-crm' ) : __( 'Updated', 'zero-bs-crm' ) ); + // zbs-not-urgent means it'll auto hide after 1.5s + $msg = zeroBSCRM_UI2_messageHTML( 'info olive mini zbs-not-urgent', $message, '', 'address book outline', 'companyUpdated' ); - $msg = zeroBSCRM_UI2_messageHTML('info orange mini',__('Email could not be updated. (A record already exists with this email address).',"zero-bs-crm").$viewHTML,'','address book outline','companyNotUpdated'); + // quick + dirty + global $zbs; - $zbs->pageMessages[] = $msg; + $zbs->pageMessages[] = $msg; + } - } - } + public function updateEmailDupeMessage( $otherCompanyID = -1 ) { + global $zbs; -/* ====================================================== - / Company Metabox - ====================================================== */ + $viewHTML = ' ' . __( 'View', 'zero-bs-crm' ) . ' ' . $this->coOrgLabel . ''; + $msg = zeroBSCRM_UI2_messageHTML( 'info orange mini', __( 'Email could not be updated. (A record already exists with this email address).', 'zero-bs-crm' ) . $viewHTML, '', 'address book outline', 'companyNotUpdated' ); -/* ====================================================== - "Contacts at Company" Metabox - ====================================================== */ + $zbs->pageMessages[] = $msg; + } +} -class zeroBS__Metabox_CompanyContacts extends zeroBS__Metabox{ +/* +====================================================== + / Company Metabox + ====================================================== */ - private $coOrgLabel = ''; +/* +====================================================== + "Contacts at Company" Metabox + ====================================================== */ - public function __construct( $plugin_file ) { +class zeroBS__Metabox_CompanyContacts extends zeroBS__Metabox { - // oldschool. - $this->coOrgLabel = jpcrm_label_company(); - - $this->objType = 'company'; - $this->metaboxID = 'zerobs-company-contacts'; - $this->metaboxTitle = __('Associated Contacts',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-company-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'high'; - $this->headless = false; - //$this->metaboxClasses = ''; - $this->capabilities = array( + private $coOrgLabel = ''; - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => false, // can be minimised - 'can_move' => false // can be moved + public function __construct( $plugin_file ) { - ); + // oldschool. + $this->coOrgLabel = jpcrm_label_company(); - - // hide if "new" (not edit) - as can't yet add this way - $isEdit = false; - if (isset($_GET['action']) && $_GET['action'] == 'edit' && isset($_GET['zbsid']) && !empty($_GET['zbsid'])) $isEdit = true; - - if ($isEdit){ - // call this - $this->initMetabox(); - } + $this->objType = 'company'; + $this->metaboxID = 'zerobs-company-contacts'; + $this->metaboxTitle = __( 'Associated Contacts', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-company-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'high'; + $this->headless = false; + // $this->metaboxClasses = ''; + $this->capabilities = array( - } + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => false, // can be minimised + 'can_move' => false, // can be moved - public function html( $company, $metabox ) { + ); - global $zbs; + // hide if "new" (not edit) - as can't yet add this way + $isEdit = false; + if ( isset( $_GET['action'] ) && $_GET['action'] == 'edit' && isset( $_GET['zbsid'] ) && ! empty( $_GET['zbsid'] ) ) { + $isEdit = true; + } - $coID = -1; if (is_array($company) && isset($company['id'])) $coID = (int)$company['id']; + if ( $isEdit ) { + // call this + $this->initMetabox(); + } + } - //$contacts = zeroBS_getCustomers(true,1000,0,false,false,'',false,false,$coID); - $contacts = array(); - if ($coID > 0){ - $contacts = $zbs->DAL->contacts->getContacts(array( + public function html( $company, $metabox ) { - 'inCompany' => $coID, + global $zbs; - 'sortByField' => 'ID', - 'sortOrder' => 'ASC', - 'page' => 0, - 'perPage' => 200, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) + $coID = -1; + if ( is_array( $company ) && isset( $company['id'] ) ) { + $coID = (int) $company['id']; + } - )); - } + // $contacts = zeroBS_getCustomers(true,1000,0,false,false,'',false,false,$coID); + $contacts = array(); + if ( $coID > 0 ) { + $contacts = $zbs->DAL->contacts->getContacts( + array( + 'inCompany' => $coID, - #} JUST OUTPUT + 'sortByField' => 'ID', + 'sortOrder' => 'ASC', + 'page' => 0, + 'perPage' => 200, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - ?> + ) + ); + } - + - // PerfTest: zeroBSCRM_performanceTest_finishTimer('custmetabox'); - // PerfTest: zeroBSCRM_performanceTest_debugOut(); + +
- 0){ - echo '
'; + #} JUST OUTPUT - foreach ($contacts as $contact){ + ?> + - #} new view link - $contactUrl = jpcrm_esc_link('view',$contact['id'],'zerobs_customer'); + - -
+ 0 ) { + echo '
'; - #} Name - $contactName = zeroBS_customerName($contact['id'],$contact,false,false); - $contactFirstName = ''; if (isset($contact['fname'])) $contactFirstName = $contact['fname']; + foreach ( $contacts as $contact ) { - #} Description - $contactDesc = '' . __('Contact since',"zero-bs-crm").' '.zeroBSCRM_date_i18n(zeroBSCRM_getDateFormat(), $contact['createduts'], true, false); - if (isset($contact['email']) && !empty($contact['email'])) $contactDesc .= '
'.$contact['email'].''; + #} new view link + $contactUrl = jpcrm_esc_link( 'view', $contact['id'], 'zerobs_customer' ); - ?>
-
-
'.esc_html($contactName).''; ?>
- -
-

-
- -
-
-
- -
-
-
' . __( 'Contact since', 'zero-bs-crm' ) . ' ' . zeroBSCRM_date_i18n( zeroBSCRM_getDateFormat(), $contact['createduts'], true, false ); + if ( isset( $contact['email'] ) && ! empty( $contact['email'] ) ) { + $contactDesc .= '
' . $contact['email'] . ''; + } - echo '
'; + ?> +
+
+
' . esc_html( $contactName ) . ''; ?>
+ +
+

+
+ +
+
+
+ +
+
+
+ '; - echo '
'; - esc_html_e('No contacts found at',"zero-bs-crm"); echo ' ' . esc_html( $this->coOrgLabel ); - echo '
'; + } else { - } + echo '
'; + esc_html_e( 'No contacts found at', 'zero-bs-crm' ); + echo ' ' . esc_html( $this->coOrgLabel ); + echo '
'; - ?> -
+ } - - + }); + + - objTypeID = ZBS_TYPE_COMPANY; - $this->objType = 'company'; - $this->metaboxID = 'zerobs-company-tags'; - $this->metaboxTitle = __(jpcrm_label_company().' Tags',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-company-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->showSuggestions = true; - $this->capabilities = array( + $this->objTypeID = ZBS_TYPE_COMPANY; + $this->objType = 'company'; + $this->metaboxID = 'zerobs-company-tags'; + $this->metaboxTitle = __( jpcrm_label_company() . ' Tags', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-company-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->showSuggestions = true; + $this->capabilities = array( - 'can_hide' => true, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true // can be minimised + 'can_hide' => true, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised - ); + ); - // call this - $this->initMetabox(); + // call this + $this->initMetabox(); + } - } - - // html + save dealt with by parent class :) + // html + save dealt with by parent class :) } -/* ====================================================== - / Create Tags Box - ====================================================== */ - -/* ====================================================== - Attach files to company metabox - ====================================================== */ - - class zeroBS__Metabox_CompanyFiles extends zeroBS__Metabox{ - - public function __construct( $plugin_file ) { - - $this->objType = 'company'; - $this->metaboxID = 'zerobs-company-files'; - $this->metaboxTitle = __('Files',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-company-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->capabilities = array( - - 'can_hide' => true, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => true, // can be added as tab - 'can_minimise' => true // can be minimised - - ); - - // call this - $this->initMetabox(); - - } +/* +====================================================== + / Create Tags Box + ====================================================== */ - public function html( $company, $metabox ) { +/* +====================================================== + Attach files to company metabox + ====================================================== */ - global $zbs; +class zeroBS__Metabox_CompanyFiles extends zeroBS__Metabox { - $html = ''; - $companyID = -1; if (is_array($company) && isset($company['id'])) $companyID = (int)$company['id']; - $zbsFiles = zeroBSCRM_files_getFiles('company',$companyID); + public function __construct( $plugin_file ) { - ?> + $this->objType = 'company'; + $this->metaboxID = 'zerobs-company-files'; + $this->metaboxTitle = __( 'Files', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-company-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'low'; + $this->capabilities = array( - true, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => true, // can be added as tab + 'can_minimise' => true, // can be minimised - #} Whole file delete method could do with rewrite - #} Also sort JS into something usable - should be ajax all this + ); - #} Any existing - if (is_array($zbsFiles) && count($zbsFiles) > 0){ - ?> - + #} Any existing + if ( is_array( $zbsFiles ) && count( $zbsFiles ) > 0 ) { + ?> + + + - '; - - ?> - + $html .= ''; - -
- - - - - - - - initMetabox(); + } - /* $file = basename($zbsFile['file']); + public function html( $company, $metabox ) { - // if in privatised system, ignore first hash in name - if (isset($zbsFile['priv'])){ + global $zbs; - $file = substr($file,strpos($file, '-')+1); - } */ - $file = zeroBSCRM_files_baseName($zbsFile['file'],isset($zbsFile['priv'])); + $html = ''; + $companyID = -1; + if ( is_array( $company ) && isset( $company['id'] ) ) { + $companyID = (int) $company['id']; + } + $zbsFiles = zeroBSCRM_files_getFiles( 'company', $companyID ); - $fileEditUrl = admin_url('admin.php?page='.$zbs->slugs['editfile']) . "&company=".$companyID."&fileid=" . ($fileLineIndx-1); + ?> +
- echo ''; - echo ''; - echo ''; // '.__('Edit','zero-bs-crm').' - $fileLineIndx++; - - } ?> -
'; + ".__('Shown on Portal','zero-bs-crm').'

'; - }else{ - echo "

".__('Not shown on Portal','zero-bs-crm').'

'; - } - }*/ + #} Whole file delete method could do with rewrite + #} Also sort JS into something usable - should be ajax all this - echo '
'.esc_html__('Delete','zero-bs-crm').'
-
+ + + + + + + + slugs['editfile'] ) . '&company=' . $companyID . '&fileid=' . ( $fileLineIndx - 1 ); + + echo ''; + echo ''; + echo ''; // '.__('Edit','zero-bs-crm').' + ++$fileLineIndx; + + } + ?> +
'; + + // if using portal.. state shown/hidden + // this is also shown in each file slot :) if you change any of it change that too + /* + if(defined('ZBS_CLIENTPRO_TEMPLATES')){ + if(isset($zbsFile['portal']) && $zbsFile['portal']){ + echo "

".__('Shown on Portal','zero-bs-crm').'

'; + }else{ + echo "

".__('Not shown on Portal','zero-bs-crm').'

'; + } + }*/ + + echo '
' . esc_html__( 'Delete', 'zero-bs-crm' ) . '
+

()
:
- +

()
:
+ +
+ - + coOrgLabel = jpcrm_label_company(); -/* ====================================================== - Company Actions Metabox Metabox - ====================================================== */ + // set these + $this->objType = 'company'; + $this->metaboxID = 'zerobs-company-actions'; + $this->metaboxTitle = jpcrm_label_company() . ' ' . __( 'Actions', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-company-edit'; + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( - class zeroBS__Metabox_CompanyActions extends zeroBS__Metabox{ + 'can_hide' => false, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - private $coOrgLabel = ''; + ); - public function __construct( $plugin_file ) { + // call this + $this->initMetabox(); + } - // oldschool. - $this->coOrgLabel = jpcrm_label_company(); + public function html( $company, $metabox ) { - // set these - $this->objType = 'company'; - $this->metaboxID = 'zerobs-company-actions'; - $this->metaboxTitle = jpcrm_label_company().' '.__('Actions','zero-bs-crm'); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-company-edit'; - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( + ?> +
- 'can_hide' => false, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved +
- ); + initMetabox(); + // localise ID & content + $companyID = -1; + if ( is_array( $company ) && isset( $company['id'] ) ) { + $companyID = (int) $company['id']; + } - } + #} if a saved post... + // if (isset($post->post_status) && $post->post_status != "auto-draft"){ + if ( $companyID > 0 ) { // existing - public function html( $company, $metabox ) { + ?> - ?>
+
-
+ - post_status) && $post->post_status != "auto-draft"){ - if ($companyID > 0){ // existing + // for now just check if can modify, later better, granular perms. + if ( zeroBSCRM_permsQuotes() ) { + ?> +
+ +
+ + +
- ?> +
+ + } else { - + // NEW quote + ?> - + + - // delete? +
- // for now just check if can modify, later better, granular perms. - if ( zeroBSCRM_permsQuotes() ) { - ?>
- -
- - -
+ - +
+ +/* +====================================================== + / Company Actions Metabox + ====================================================== */ -
- - +/* +====================================================== + Company Activity Metabox + ====================================================== */ +class zeroBS__Metabox_Company_Activity extends zeroBS__Metabox { -
+ public function __construct( $plugin_file ) { - metaboxID = 'zbs-company-activity-metabox'; + $this->metaboxTitle = __( 'Activity', 'zero-bs-crm' ); + $this->metaboxIcon = 'heartbeat'; + $this->metaboxScreen = 'zerobs_view_company'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; - } + // call this + $this->initMetabox(); + } - ?>
'; + echo '
'; + $zbsCompanyActivity = zeroBSCRM_getCompanyLogs( $objid, true, 100, 0, '', false ); + zeroBSCRM_html_companyTimeline( $objid, $zbsCompanyActivity, $obj ); + echo '
'; + echo '
'; + } - public function __construct( $plugin_file ) { - - $this->metaboxID = 'zbs-company-activity-metabox'; - $this->metaboxTitle = __('Activity', 'zero-bs-crm'); - $this->metaboxIcon = 'heartbeat'; - $this->metaboxScreen = 'zerobs_view_company'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - - // call this - $this->initMetabox(); - - } - - public function html( $obj, $metabox ) { - - global $zbs; - - $objid = -1; if (is_array($obj) && isset($obj['id'])) $objid = $obj['id']; - - // no need for this, $obj will already be same $zbsCustomer = zeroBS_getCustomer($objid, true,true,true); - - echo '
'; - echo '
'; - $zbsCompanyActivity = zeroBSCRM_getCompanyLogs($objid,true,100,0,'',false); - zeroBSCRM_html_companyTimeline($objid,$zbsCompanyActivity,$obj); - echo '
'; - echo '
'; - - } - - // nothing to save here. - public function save_data( $objID, $obj ) { - return $obj; - } + // nothing to save here. + public function save_data( $objID, $obj ) { + return $obj; + } } - -/* ====================================================== - Company Activity Metabox - ====================================================== */ +/* +====================================================== + Company Activity Metabox + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Contacts.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Contacts.php index ce5a87fa4ace..c8432e6894b8 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Contacts.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Contacts.php @@ -1,5 +1,5 @@ - 0) foreach ($settings['customersfiles'] as $cfb){ + if (isset($settings['customersfiles']) && is_array($settings['customersfiles']) && count($settings['customersfiles']) > 0) foreach ($settings['customersfiles'] as $cfb){ - $cfbName = ''; if (isset($cfb[0])) $cfbName = $cfb[0]; + $cfbName = ''; if (isset($cfb[0])) $cfbName = $cfb[0]; - //add_meta_box('zerobs-customer-files-'.$cfbInd, $cfbName, 'zeroBS__MetaboxFilesCustom', 'zerobs_customer', 'normal', 'low',$cfbName); - $zeroBS__Metabox_ContactCustomFiles = new zeroBS__Metabox_ContactCustomFiles( __FILE__, 'zerobs-customer-files-'.$cfbInd , $cfbName); - - $cfbInd++; - } */ + //add_meta_box('zerobs-customer-files-'.$cfbInd, $cfbName, 'zeroBS__MetaboxFilesCustom', 'zerobs_customer', 'normal', 'low',$cfbName); + $zeroBS__Metabox_ContactCustomFiles = new zeroBS__Metabox_ContactCustomFiles( __FILE__, 'zerobs-customer-files-'.$cfbInd , $cfbName); - $fileSlots = zeroBSCRM_fileSlots_getFileSlots(); - if (count($fileSlots) > 0) foreach ($fileSlots as $fs){ + $cfbInd++; + } */ - $zeroBS__Metabox_ContactCustomFiles = new zeroBS__Metabox_ContactCustomFiles( __FILE__, 'zerobs-customer-files-'.$fs['key'] , $fs['name']); - - } + $fileSlots = zeroBSCRM_fileSlots_getFileSlots(); + if ( count( $fileSlots ) > 0 ) { + foreach ( $fileSlots as $fs ) { - } + $zeroBS__Metabox_ContactCustomFiles = new zeroBS__Metabox_ContactCustomFiles( __FILE__, 'zerobs-customer-files-' . $fs['key'], $fs['name'] ); - #} Social - if (zeroBSCRM_getSetting('usesocial') == "1") $zeroBS__Metabox_ContactSocial = new zeroBS__Metabox_ContactSocial( __FILE__ ); + } + } + } - #} AKA - if (zeroBSCRM_getSetting('useaka') == "1") $zeroBS__Metabox_ContactAKA = new zeroBS__Metabox_ContactAKA( __FILE__ ); + #} Social + if ( zeroBSCRM_getSetting( 'usesocial' ) == '1' ) { + $zeroBS__Metabox_ContactSocial = new zeroBS__Metabox_ContactSocial( __FILE__ ); + } - #} Ownership - if (zeroBSCRM_getSetting('perusercustomers') == "1") $zeroBS__Metabox_Ownership = new zeroBS__Metabox_Ownership( __FILE__, ZBS_TYPE_CONTACT); + #} AKA + if ( zeroBSCRM_getSetting( 'useaka' ) == '1' ) { + $zeroBS__Metabox_ContactAKA = new zeroBS__Metabox_ContactAKA( __FILE__ ); + } - #} B2B mode (assign to co) - if (zeroBSCRM_getSetting('companylevelcustomers') == "1") $zeroBS__Metabox_ContactCompany = new zeroBS__Metabox_ContactCompany( __FILE__ ); - - } + #} Ownership + if ( zeroBSCRM_getSetting( 'perusercustomers' ) == '1' ) { + $zeroBS__Metabox_Ownership = new zeroBS__Metabox_Ownership( __FILE__, ZBS_TYPE_CONTACT ); + } + #} B2B mode (assign to co) + if ( zeroBSCRM_getSetting( 'companylevelcustomers' ) == '1' ) { + $zeroBS__Metabox_ContactCompany = new zeroBS__Metabox_ContactCompany( __FILE__ ); + } + } - // Activity box on view page - if ( zeroBSCRM_is_customer_view_page() ) { + // Activity box on view page + if ( zeroBSCRM_is_customer_view_page() ) { $zeroBS__Metabox_Contact_Activity = new zeroBS__Metabox_Contact_Activity( __FILE__ ); - if ( zeroBSCRM_isExtensionInstalled( 'portal' ) ) { - $zeroBS__Metabox_ContactPortal = new zeroBS__Metabox_ContactPortal( __FILE__, 'zbs-view-contact' ); - } + if ( zeroBSCRM_isExtensionInstalled( 'portal' ) ) { + $zeroBS__Metabox_ContactPortal = new zeroBS__Metabox_ContactPortal( __FILE__, 'zbs-view-contact' ); } } +} - add_action( 'admin_init', 'zeroBSCRM_CustomersMetaboxSetup' ); - - -/* ====================================================== - / Init Func - ====================================================== */ - - + add_action( 'admin_init', 'zeroBSCRM_CustomersMetaboxSetup' ); -/* ====================================================== - Declare Globals - ====================================================== */ +/* +====================================================== + / Init Func + ====================================================== */ - #} Used throughout - // Don't know who added this, but GLOBALS are out of scope here - //global $zbsCustomerFields,$zbsCustomerQuoteFields,$zbsCustomerInvoiceFields; +/* +====================================================== + Declare Globals + ====================================================== */ -/* ====================================================== - / Declare Globals - ====================================================== */ + #} Used throughout + // Don't know who added this, but GLOBALS are out of scope here + // global $zbsCustomerFields,$zbsCustomerQuoteFields,$zbsCustomerInvoiceFields; +/* +====================================================== + / Declare Globals + ====================================================== */ - // PerfTest: zeroBSCRM_performanceTest_startTimer('custmetabox'); + // PerfTest: zeroBSCRM_performanceTest_startTimer('custmetabox'); -/* ====================================================== - Customer Metabox - ====================================================== */ +/* +====================================================== + Customer Metabox + ====================================================== */ - class zeroBS__Metabox_Contact extends zeroBS__Metabox{ - - // this is for catching 'new' contacts - private $newRecordNeedsRedir = false; +class zeroBS__Metabox_Contact extends zeroBS__Metabox { - public function __construct( $plugin_file ) { + // this is for catching 'new' contacts + private $newRecordNeedsRedir = false; - // set these - $this->objType = 'contact'; - $this->metaboxID = 'zerobs-customer-edit'; - $this->metaboxTitle = __('Contact Details',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( + public function __construct( $plugin_file ) { - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved + // set these + $this->objType = 'contact'; + $this->metaboxID = 'zerobs-customer-edit'; + $this->metaboxTitle = __( 'Contact Details', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( - ); + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - // call this - $this->initMetabox(); + ); - } + // call this + $this->initMetabox(); + } /** * This method generates HTML content for contact and metadata. @@ -303,27 +311,29 @@ public function html( $contact, $metabox ) { // phpcs:ignore VariableAnalysis.Co '; + // debug if (get_current_user_id() == 12) echo 'FIRING
'; - define('ZBS_C_SAVED',1); + define( 'ZBS_C_SAVED', 1 ); - global $zbs; + global $zbs; + + // check this + if ( empty( $contact_id ) || $contact_id < 1 ) { + $contact_id = -1; + } - // check this - if (empty($contact_id) || $contact_id < 1) $contact_id = -1; - - $dataArr = zeroBS_buildContactMeta($_POST); + $dataArr = zeroBS_buildContactMeta( $_POST ); - // Use the tag-class function to retrieve any tags so we can add inline. - // Save tags against objid - $dataArr['tags'] = zeroBSCRM_tags_retrieveFromPostBag(true,ZBS_TYPE_CONTACT); + // Use the tag-class function to retrieve any tags so we can add inline. + // Save tags against objid + $dataArr['tags'] = zeroBSCRM_tags_retrieveFromPostBag( true, ZBS_TYPE_CONTACT ); - // owner - saved here now, rather than ownership box, to allow for pre-hook update. (as tags) - $owner = -1; + // owner - saved here now, rather than ownership box, to allow for pre-hook update. (as tags) + $owner = -1; // Only allow an existing contact to change owners if they have permission to do so. if ( $contact_id > -1 ) { @@ -344,348 +354,364 @@ public function save_data( $contact_id, $contact ) { } } - // now we check whether a user with this email already exists (separate to this contact id), so we can warn them - // ... that it wont have changed the email - if ( !empty( $dataArr['email'] ) ) { - - if ( !zeroBSCRM_validateEmail( $dataArr['email'] ) ) { - - $this->update_invalid_email( $dataArr['email'] ); - $dataArr['email'] = ''; - - } else { - - $potentialID = zeroBS_getCustomerIDWithEmail( $dataArr['email'] ); - - if ( !empty( $potentialID ) && $potentialID != $contact_id ) { - - // no go. - $this->updateEmailDupeMessage( $potentialID ); - - // unset email change (leave as was) - $dataArr['email'] = zeroBS_customerEmail( $contact_id ); - - } - } - - } - // phpcs:disable WordPress.NamingConventions.ValidVariableName -- to be refactored. - // We have to explicitly retrieve the avatar from the DB. - $dataArr['avatar'] = ( $contact_id !== -1 ) ? $zbs->DAL->contacts->getContactAvatar( $contact_id ) : ''; - //phpcs:enable WordPress.NamingConventions.ValidVariableName - - // make a copy for IA below (just fields) - $contactData = $dataArr; - - // Company assignment? - if (isset($_POST['zbs_company'])) $dataArr['companies'] = array((int)sanitize_text_field($_POST['zbs_company'])); - - // Stripslashes - // This avoids us adding `O\'toole ltd' into the db. see #1107 - // ...this is more sensitive than using zeroBSCRM_stripSlashesFromArr - // in the long term it may make more sense to stripslashes pre insert/update in the DAL - // in the case of contacts, there are no core fields which will be broken by stripslashes at this time (4.0.11) - $data_array = $dataArr; - foreach ($dataArr as $key => $val){ - - // op strings - $value = $val; - if ( is_string( $value ) ) $value = stripslashes( $value ); - - // pass into final array - $data_array[$key] = $value; - - } - - // add update directly - $addUpdateReturn = $zbs->DAL->contacts->addUpdateContact(array( - - 'id' => $contact_id, - 'owner' => $owner, - 'data' => $data_array, - 'limitedFields' => -1, - /* array( - - 'email' => $userDeets['email'], // Unique Field ! - - 'status' => $userDeets['status'], - 'prefix' => $userDeets['prefix'], - 'fname' => $userDeets['fname'], - 'lname' => $userDeets['lname'], - 'addr1' => $userDeets['addr1'], - 'addr2' => $userDeets['addr2'], - 'city' => $userDeets['city'], - 'county' => $userDeets['county'], - 'country' => $userDeets['country'], - 'postcode' => $userDeets['postcode'], - 'secaddr1' => $userDeets['secaddr_addr1'], - 'secaddr2' => $userDeets['secaddr_addr2'], - 'seccity' => $userDeets['secaddr_city'], - 'seccounty' => $userDeets['secaddr_county'], - 'seccountry' => $userDeets['secaddr_country'], - 'secpostcode' => $userDeets['secaddr_postcode'], - 'hometel' => $userDeets['hometel'], - 'worktel' => $userDeets['worktel'], - 'mobtel' => $userDeets['mobtel'], - 'wpid' => -1, - 'avatar' => $avatarURL, - - // Note Custom fields may be passed here, but will not have defaults so check isset() - - 'tags' => $tags, - - // wh added for later use. - 'lastcontacted' => $lastcontacted, - - 'companies' => $companies // array of co id's :) - ) */ - - )); - - // Note: For NEW contacts, we make sure a global is set here, that other update funcs can catch - // ... so it's essential this one runs first! - // this is managed in the metabox Class :) - if ($contact_id == -1 && !empty($addUpdateReturn) && $addUpdateReturn != -1) { - - $contact_id = $addUpdateReturn; - global $zbsJustInsertedMetaboxID; $zbsJustInsertedMetaboxID = $contact_id; - - // set this so it redirs - $this->newRecordNeedsRedir = true; - } - - // success? - if ($addUpdateReturn != -1 && $addUpdateReturn > 0){ - $this->save_profile_picture( $contact_id, $contact ); - // Update Msg - // this adds an update message which'll go out ahead of any content - // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); - // This adds to edit page - $this->updateMessage( $this->newRecordNeedsRedir ); - - // catch any non-critical messages - $nonCriticalMessages = $zbs->DAL->getErrors(ZBS_TYPE_CONTACT); - if (is_array($nonCriticalMessages) && count($nonCriticalMessages) > 0) $this->dalNoticeMessage($nonCriticalMessages); - - } else { - - // fail somehow - $failMessages = $zbs->DAL->getErrors(ZBS_TYPE_CONTACT); - - // show msg (retrieved from DAL err stack) - if (is_array($failMessages) && count($failMessages) > 0) - $this->dalErrorMessage($failMessages); - else - $this->dalErrorMessage(array(__('Insert/Update Failed with general error','zero-bs-crm'))); - - // pass the pre-fill: - global $zbsObjDataPrefill; $zbsObjDataPrefill = $dataArr; - - - } - - } - - return $contact; - } - - /* - * Saves the profile picture - */ - public function save_profile_picture( $contact_id, $crm_contact ) { - global $zbs; - - $contact_dir_info = jpcrm_storage_dir_info_for_contact( $contact_id ); - $field_key = 'jpcrm-profile-picture'; - $is_remove_flag_set = isset( $_POST['zbsc_remove-profile-picture'] ) && $_POST['zbsc_remove-profile-picture'] == '1'; - $remove_old_avatar = false; - $has_new_avatar_file = - isset( $_FILES['zbsc_profile-picture-file'] ) - && empty( $_FILES['zbsc_profile-picture-file']['error'] ) - && is_uploaded_file( $_FILES['zbsc_profile-picture-file']['tmp_name'] ); - - if ( $is_remove_flag_set ) { - $zbs->DAL->contacts->addUpdateContact( array( - 'id' => $contact_id, - 'limitedFields' => array( - array( - 'key' => 'zbsc_avatar', - 'val' => '', - 'type' => '%s' - ) - ) - )); - $remove_old_avatar = true; - } else if ( $has_new_avatar_file ) { - - // verify image file type - $allowed_image_types = array('image/jpeg' => 'jpg', 'image/jpg' => 'jpg', 'image/gif' => 'gif', 'image/png' => 'png'); - $allowed_file_extensions = array( '.jpg', '.jpeg', '.gif', '.png' ); - $allowed_mime_types = array( 'image/jpeg','image/jpg', 'image/gif', 'image/png' ); - if ( !jpcrm_file_check_mime_extension( $_FILES['zbsc_profile-picture-file'], $allowed_file_extensions, $allowed_mime_types ) ){ - - $this->dalErrorMessage ( array( __( 'Error: Profile Picture only accepts jpg, png, and gif images!', 'zero-bs-crm' ) ) ); - return; - - } - - if ( $contact_dir_info === false ) { - $this->dalErrorMessage ( array( __( 'Error while retrieving the contact\'s folder.', 'zero-bs-crm' ) ) ); - return; - } - - $avatar_path = $contact_dir_info['avatar']['path']; - $contact_folder_exists = jpcrm_create_and_secure_dir_from_external_access( $avatar_path, false ); - - if ( ! $contact_folder_exists ) { - $this->dalErrorMessage ( array( __( 'There was an error creating the profile picture directory.', 'zero-bs-crm' ) ) ); - return; - } - - $zbs->load_encryption(); - $avatar_filename = sprintf( - 'avatar_%s.%s', - $zbs->encryption->get_rand_hex( 10 ), - $allowed_image_types[ $_FILES['zbsc_profile-picture-file']['type'] ] // extension for this filetype - ); - - if ( - ! file_exists( $avatar_path . '/' . $avatar_filename ) - && move_uploaded_file( $_FILES['zbsc_profile-picture-file']['tmp_name'], $avatar_path . '/' . $avatar_filename) - ) { - $zbs->DAL->contacts->addUpdateContact( array( - 'id' => $contact_id, - 'limitedFields' => array( - array( - 'key' => 'zbsc_avatar', - 'val' => $contact_dir_info['avatar']['url'] . '/' . $avatar_filename, - 'type' => '%s' - ) - ) - )); - - $remove_old_avatar = true; - } else { - $this->dalErrorMessage ( array( __( 'There was an error updating the profile picture.', 'zero-bs-crm' ) ) ); - } - } - - if ( $remove_old_avatar && ! empty( $crm_contact['avatar'] ) ) { - $previous_avatar_full_path = $contact_dir_info['avatar']['path'] . '/' . basename( $crm_contact['avatar'] ); - if ( file_exists( $previous_avatar_full_path ) ) { - unlink( $previous_avatar_full_path ); - } - } - } - - // This catches 'new' contacts + redirs to right url - public function post_save_data($objID,$obj){ - - if ($this->newRecordNeedsRedir){ - - global $zbs, $zbsJustInsertedMetaboxID; - if (!empty($zbsJustInsertedMetaboxID) && $zbsJustInsertedMetaboxID > 0){ - - // redir - $zbs->new_record_edit_redirect( 'zerobs_customer', $zbsJustInsertedMetaboxID ); - } - - } - - } - - public function updateMessage( $created = false ){ - $text = $created ? __('Contact Created',"zero-bs-crm") : __('Contact Updated',"zero-bs-crm"); - // zbs-not-urgent means it'll auto hide after 1.5s - $msg = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',$text,'','address book outline','contactUpdated'); - - // quick + dirty - global $zbs; - - $zbs->pageMessages[] = $msg; - - } - - public function update_invalid_email( $invalid_email ) { - global $zbs; - $msg = zeroBSCRM_UI2_messageHTML( - 'info orange mini', - sprintf( __( 'The contact email specified (%s) is not valid.', 'zero-bs-crm' ), $invalid_email ), - '', - 'address book outline', - 'contactUpdated' - ); - $zbs->pageMessages[] = $msg; - } - - public function updateEmailDupeMessage($otherContactID=-1){ - - $viewHTML = ' '.__('View Contact','zero-bs-crm').''; - - $msg = zeroBSCRM_UI2_messageHTML('info orange mini',__('Contact email could not be updated because a contact already exists with this email address.',"zero-bs-crm").$viewHTML,'','address book outline','contactUpdated'); - - // quick + dirty - global $zbs; - - $zbs->pageMessages[] = $msg; - - } - } - -/* ====================================================== - / Customer Metabox - ====================================================== */ - - -/* ====================================================== - Create Actions Box - ====================================================== */ - -class zeroBS__Metabox_ContactActions extends zeroBS__Metabox{ - - private $actions = array(); - - public function __construct( $plugin_file ) { - - $this->objType = 'contact'; - $this->metaboxID = 'zerobs-customer-actions'; - $this->metaboxTitle = __('Contact Actions',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->headless = true; - $this->capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => false, // can be minimised - 'can_move' => false // can be moved + // now we check whether a user with this email already exists (separate to this contact id), so we can warn them + // ... that it wont have changed the email + if ( ! empty( $dataArr['email'] ) ) { - ); + if ( ! zeroBSCRM_validateEmail( $dataArr['email'] ) ) { - // hacky id check for now: - if (isset($_GET['zbsid']) && !empty($_GET['zbsid'])) { - $id = (int)sanitize_text_field($_GET['zbsid']); - // call this, if actions - $this->actions = zeroBS_contact_actions($id); + $this->update_invalid_email( $dataArr['email'] ); + $dataArr['email'] = ''; + + } else { + + $potentialID = zeroBS_getCustomerIDWithEmail( $dataArr['email'] ); + + if ( ! empty( $potentialID ) && $potentialID != $contact_id ) { + + // no go. + $this->updateEmailDupeMessage( $potentialID ); + + // unset email change (leave as was) + $dataArr['email'] = zeroBS_customerEmail( $contact_id ); + + } + } + } + // phpcs:disable WordPress.NamingConventions.ValidVariableName -- to be refactored. + // We have to explicitly retrieve the avatar from the DB. + $dataArr['avatar'] = ( $contact_id !== -1 ) ? $zbs->DAL->contacts->getContactAvatar( $contact_id ) : ''; + //phpcs:enable WordPress.NamingConventions.ValidVariableName + + // make a copy for IA below (just fields) + $contactData = $dataArr; + + // Company assignment? + if ( isset( $_POST['zbs_company'] ) ) { + $dataArr['companies'] = array( (int) sanitize_text_field( $_POST['zbs_company'] ) ); + } + + // Stripslashes + // This avoids us adding `O\'toole ltd' into the db. see #1107 + // ...this is more sensitive than using zeroBSCRM_stripSlashesFromArr + // in the long term it may make more sense to stripslashes pre insert/update in the DAL + // in the case of contacts, there are no core fields which will be broken by stripslashes at this time (4.0.11) + $data_array = $dataArr; + foreach ( $dataArr as $key => $val ) { + + // op strings + $value = $val; + if ( is_string( $value ) ) { + $value = stripslashes( $value ); + } + + // pass into final array + $data_array[ $key ] = $value; + + } + + // add update directly + $addUpdateReturn = $zbs->DAL->contacts->addUpdateContact( + array( + + 'id' => $contact_id, + 'owner' => $owner, + 'data' => $data_array, + 'limitedFields' => -1, + /* + array( + + 'email' => $userDeets['email'], // Unique Field ! + + 'status' => $userDeets['status'], + 'prefix' => $userDeets['prefix'], + 'fname' => $userDeets['fname'], + 'lname' => $userDeets['lname'], + 'addr1' => $userDeets['addr1'], + 'addr2' => $userDeets['addr2'], + 'city' => $userDeets['city'], + 'county' => $userDeets['county'], + 'country' => $userDeets['country'], + 'postcode' => $userDeets['postcode'], + 'secaddr1' => $userDeets['secaddr_addr1'], + 'secaddr2' => $userDeets['secaddr_addr2'], + 'seccity' => $userDeets['secaddr_city'], + 'seccounty' => $userDeets['secaddr_county'], + 'seccountry' => $userDeets['secaddr_country'], + 'secpostcode' => $userDeets['secaddr_postcode'], + 'hometel' => $userDeets['hometel'], + 'worktel' => $userDeets['worktel'], + 'mobtel' => $userDeets['mobtel'], + 'wpid' => -1, + 'avatar' => $avatarURL, + + // Note Custom fields may be passed here, but will not have defaults so check isset() + + 'tags' => $tags, + + // wh added for later use. + 'lastcontacted' => $lastcontacted, + + 'companies' => $companies // array of co id's :) + ) */ + + ) + ); + + // Note: For NEW contacts, we make sure a global is set here, that other update funcs can catch + // ... so it's essential this one runs first! + // this is managed in the metabox Class :) + if ( $contact_id == -1 && ! empty( $addUpdateReturn ) && $addUpdateReturn != -1 ) { + + $contact_id = $addUpdateReturn; + global $zbsJustInsertedMetaboxID; + $zbsJustInsertedMetaboxID = $contact_id; + + // set this so it redirs + $this->newRecordNeedsRedir = true; + } + + // success? + if ( $addUpdateReturn != -1 && $addUpdateReturn > 0 ) { + $this->save_profile_picture( $contact_id, $contact ); + // Update Msg + // this adds an update message which'll go out ahead of any content + // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); + // This adds to edit page + $this->updateMessage( $this->newRecordNeedsRedir ); + + // catch any non-critical messages + $nonCriticalMessages = $zbs->DAL->getErrors( ZBS_TYPE_CONTACT ); + if ( is_array( $nonCriticalMessages ) && count( $nonCriticalMessages ) > 0 ) { + $this->dalNoticeMessage( $nonCriticalMessages ); + } + } else { + + // fail somehow + $failMessages = $zbs->DAL->getErrors( ZBS_TYPE_CONTACT ); + + // show msg (retrieved from DAL err stack) + if ( is_array( $failMessages ) && count( $failMessages ) > 0 ) { + $this->dalErrorMessage( $failMessages ); + } else { + $this->dalErrorMessage( array( __( 'Insert/Update Failed with general error', 'zero-bs-crm' ) ) ); + } + + // pass the pre-fill: + global $zbsObjDataPrefill; + $zbsObjDataPrefill = $dataArr; + + } + } + + return $contact; + } + + /* + * Saves the profile picture + */ + public function save_profile_picture( $contact_id, $crm_contact ) { + global $zbs; + + $contact_dir_info = jpcrm_storage_dir_info_for_contact( $contact_id ); + $field_key = 'jpcrm-profile-picture'; + $is_remove_flag_set = isset( $_POST['zbsc_remove-profile-picture'] ) && $_POST['zbsc_remove-profile-picture'] == '1'; + $remove_old_avatar = false; + $has_new_avatar_file = + isset( $_FILES['zbsc_profile-picture-file'] ) + && empty( $_FILES['zbsc_profile-picture-file']['error'] ) + && is_uploaded_file( $_FILES['zbsc_profile-picture-file']['tmp_name'] ); + + if ( $is_remove_flag_set ) { + $zbs->DAL->contacts->addUpdateContact( + array( + 'id' => $contact_id, + 'limitedFields' => array( + array( + 'key' => 'zbsc_avatar', + 'val' => '', + 'type' => '%s', + ), + ), + ) + ); + $remove_old_avatar = true; + } elseif ( $has_new_avatar_file ) { + + // verify image file type + $allowed_image_types = array( + 'image/jpeg' => 'jpg', + 'image/jpg' => 'jpg', + 'image/gif' => 'gif', + 'image/png' => 'png', + ); + $allowed_file_extensions = array( '.jpg', '.jpeg', '.gif', '.png' ); + $allowed_mime_types = array( 'image/jpeg', 'image/jpg', 'image/gif', 'image/png' ); + if ( ! jpcrm_file_check_mime_extension( $_FILES['zbsc_profile-picture-file'], $allowed_file_extensions, $allowed_mime_types ) ) { + + $this->dalErrorMessage( array( __( 'Error: Profile Picture only accepts jpg, png, and gif images!', 'zero-bs-crm' ) ) ); + return; + + } + + if ( $contact_dir_info === false ) { + $this->dalErrorMessage( array( __( 'Error while retrieving the contact\'s folder.', 'zero-bs-crm' ) ) ); + return; + } + + $avatar_path = $contact_dir_info['avatar']['path']; + $contact_folder_exists = jpcrm_create_and_secure_dir_from_external_access( $avatar_path, false ); + + if ( ! $contact_folder_exists ) { + $this->dalErrorMessage( array( __( 'There was an error creating the profile picture directory.', 'zero-bs-crm' ) ) ); + return; + } + + $zbs->load_encryption(); + $avatar_filename = sprintf( + 'avatar_%s.%s', + $zbs->encryption->get_rand_hex( 10 ), + $allowed_image_types[ $_FILES['zbsc_profile-picture-file']['type'] ] // extension for this filetype + ); + + if ( ! file_exists( $avatar_path . '/' . $avatar_filename ) + && move_uploaded_file( $_FILES['zbsc_profile-picture-file']['tmp_name'], $avatar_path . '/' . $avatar_filename ) + ) { + $zbs->DAL->contacts->addUpdateContact( + array( + 'id' => $contact_id, + 'limitedFields' => array( + array( + 'key' => 'zbsc_avatar', + 'val' => $contact_dir_info['avatar']['url'] . '/' . $avatar_filename, + 'type' => '%s', + ), + ), + ) + ); + + $remove_old_avatar = true; + } else { + $this->dalErrorMessage( array( __( 'There was an error updating the profile picture.', 'zero-bs-crm' ) ) ); + } + } + + if ( $remove_old_avatar && ! empty( $crm_contact['avatar'] ) ) { + $previous_avatar_full_path = $contact_dir_info['avatar']['path'] . '/' . basename( $crm_contact['avatar'] ); + if ( file_exists( $previous_avatar_full_path ) ) { + unlink( $previous_avatar_full_path ); + } + } + } + + // This catches 'new' contacts + redirs to right url + public function post_save_data( $objID, $obj ) { + + if ( $this->newRecordNeedsRedir ) { + + global $zbs, $zbsJustInsertedMetaboxID; + if ( ! empty( $zbsJustInsertedMetaboxID ) && $zbsJustInsertedMetaboxID > 0 ) { + + // redir + $zbs->new_record_edit_redirect( 'zerobs_customer', $zbsJustInsertedMetaboxID ); + } + } + } + + public function updateMessage( $created = false ) { + $text = $created ? __( 'Contact Created', 'zero-bs-crm' ) : __( 'Contact Updated', 'zero-bs-crm' ); + // zbs-not-urgent means it'll auto hide after 1.5s + $msg = zeroBSCRM_UI2_messageHTML( 'info olive mini zbs-not-urgent', $text, '', 'address book outline', 'contactUpdated' ); + + // quick + dirty + global $zbs; + + $zbs->pageMessages[] = $msg; + } + + public function update_invalid_email( $invalid_email ) { + global $zbs; + $msg = zeroBSCRM_UI2_messageHTML( + 'info orange mini', + sprintf( __( 'The contact email specified (%s) is not valid.', 'zero-bs-crm' ), $invalid_email ), + '', + 'address book outline', + 'contactUpdated' + ); + $zbs->pageMessages[] = $msg; + } + + public function updateEmailDupeMessage( $otherContactID = -1 ) { + + $viewHTML = ' ' . __( 'View Contact', 'zero-bs-crm' ) . ''; + + $msg = zeroBSCRM_UI2_messageHTML( 'info orange mini', __( 'Contact email could not be updated because a contact already exists with this email address.', 'zero-bs-crm' ) . $viewHTML, '', 'address book outline', 'contactUpdated' ); + + // quick + dirty + global $zbs; + + $zbs->pageMessages[] = $msg; + } +} + +/* +====================================================== + / Customer Metabox + ====================================================== */ + +/* +====================================================== + Create Actions Box + ====================================================== */ + +class zeroBS__Metabox_ContactActions extends zeroBS__Metabox { + + private $actions = array(); + + public function __construct( $plugin_file ) { + + $this->objType = 'contact'; + $this->metaboxID = 'zerobs-customer-actions'; + $this->metaboxTitle = __( 'Contact Actions', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->headless = true; + $this->capabilities = array( + + 'can_hide' => false, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => false, // can be minimised + 'can_move' => false, // can be moved + + ); + + // hacky id check for now: + if ( isset( $_GET['zbsid'] ) && ! empty( $_GET['zbsid'] ) ) { + $id = (int) sanitize_text_field( $_GET['zbsid'] ); + // call this, if actions + $this->actions = zeroBS_contact_actions( $id ); } $this->initMetabox(); } - public function html( $contact, $metabox ) { + public function html( $contact, $metabox ) { - $avatarMode = zeroBSCRM_getSetting( 'avatarmode' ); - $avatarStr = ''; + $avatarMode = zeroBSCRM_getSetting( 'avatarmode' ); + $avatarStr = ''; $is_new_contact = count( $this->actions ) > 0 ? false : true; - if ( $avatarMode !== 3 ) { + if ( $avatarMode !== 3 ) { - $cID = -1; if (is_array($contact) && isset($contact['id'])) $cID = (int)$contact['id']; - $avatarStr = zeroBS_customerAvatarHTML($cID); + $cID = -1; + if ( is_array( $contact ) && isset( $contact['id'] ) ) { + $cID = (int) $contact['id']; + } + $avatarStr = zeroBS_customerAvatarHTML( $cID ); - } + } ?>
@@ -693,147 +719,176 @@ public function html( $contact, $metabox ) {
- -
+ +
- - +
objType = 'contact'; - $this->metaboxID = 'zerobs-customer-custom-files'; - $this->metaboxTitle = __('Other Files',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->capabilities = array( + $this->objType = 'contact'; + $this->metaboxID = 'zerobs-customer-custom-files'; + $this->metaboxTitle = __( 'Other Files', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'low'; + $this->capabilities = array( - 'can_hide' => true, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => true, // can be added as tab - 'can_minimise' => true // can be minimised + 'can_hide' => true, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => true, // can be added as tab + 'can_minimise' => true, // can be minimised - ); + ); - if (!empty($idOverride)) $this->metaboxID = $idOverride; - if (!empty($titleOverride)) $this->metaboxTitle = __($titleOverride,"zero-bs-crm"); - - // call this - $this->initMetabox(); + if ( ! empty( $idOverride ) ) { + $this->metaboxID = $idOverride; + } + if ( ! empty( $titleOverride ) ) { + $this->metaboxTitle = __( $titleOverride, 'zero-bs-crm' ); + } - } + // call this + $this->initMetabox(); + } - public function html( $contact, $args ) { + public function html( $contact, $args ) { - global $zbs; + global $zbs; - $html = ''; + $html = ''; - $thisFileSlotName = ''; if (isset($args['title'])) $thisFileSlotName = $args['title']; - $filePerma = ''; if (isset($thisFileSlotName) && !empty($thisFileSlotName)) { - //$filePerma = strtolower(str_replace(' ','_',str_replace('.','_',substr($thisFileSlotName,0,20)))); - $filePerma = $zbs->DAL->makeSlug($thisFileSlotName); - } + $thisFileSlotName = ''; + if ( isset( $args['title'] ) ) { + $thisFileSlotName = $args['title']; + } + $filePerma = ''; if ( isset( $thisFileSlotName ) && ! empty( $thisFileSlotName ) ) { + // $filePerma = strtolower(str_replace(' ','_',str_replace('.','_',substr($thisFileSlotName,0,20)))); + $filePerma = $zbs->DAL->makeSlug( $thisFileSlotName ); + } // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $zbsFiles = array(); @@ -864,1624 +919,1723 @@ public function html( $contact, $args ) { } // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - ?> - - - 0){ - ?> - + - public function save_data( $contact_id, $contact ) { + +
- + - /* $file = basename($zbsFile['file']); + 0 ) { + ?> + + + $file = substr($file,strpos($file, '-')+1); + } */ + $file = zeroBSCRM_files_baseName( $zbsFile['file'], isset( $zbsFile['priv'] ) ); + echo ''; - " . esc_html__( 'Shown on Portal', 'zero-bs-crm' ) . '

'; + } else { + echo "

" . esc_html__( 'Not shown on Portal', 'zero-bs-crm' ) . '

'; + } + } + ++$fileLineIndx; - // will be done by mainfunc wp_nonce_field(plugin_basename(__FILE__), 'zbsc_file_attachment_nonce'); - - $html .= ''; - - ?> - - - -
+ '. esc_html( $file ) .' '; - - // if using portal.. state shown/hidden - // this is also shown in each file slot :) if you change any of it change that too - if(defined('ZBS_CLIENTPRO_TEMPLATES')){ - if(isset($zbsFile['portal']) && $zbsFile['portal']){ - echo "

".esc_html__('Shown on Portal','zero-bs-crm').'

'; - }else{ - echo "

".esc_html__('Not shown on Portal','zero-bs-crm').'

'; - } - } - - $fileLineIndx++; + /* + $file = basename($zbsFile['file']); - } ?> -

()
:
- - + '; - } + ?> +

()
:
+ +
+ + - if (isset($settings['customersfiles']) && is_array($settings['customersfiles']) && count($settings['customersfiles']) > 0) foreach ($settings['customersfiles'] as $cfb){ + DAL->makeSlug($thisFileSlotName); + public function save_data( $contact_id, $contact ) { - } + // when multiple custom file boxes, this only needs to fire once :) + if ( zeroBSCRM_is_customer_edit_page() && ! defined( 'ZBS_CUSTOMFILES_SAVED' ) ) { - if (!empty($thisFileSlotName) && !empty($filePerma)) $cfbsubs[$filePerma] = $thisFileSlotName; - - } + define( 'ZBS_CUSTOMFILES_SAVED', 1 ); - if (count($cfbsubs) > 0) foreach ($cfbsubs as $cfSubKey => $cfSubName){ + global $zbsc_justUploadedCustomer, $zbs; + $settings = $zbs->settings->get( 'customfields' ); + $cfbInd = 1; - /* --- security verification --- */ - if (isset($_POST['zbsc_file_attachment_nonce'])) if(!wp_verify_nonce($_POST['zbsc_file_attachment_nonce'], plugin_basename(__FILE__))) { - return $contact_id; - } // end if - - if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { - return $contact_id; - } // end if + $cfbsubs = array(); - if (!zeroBSCRM_permsCustomers()){ - return $contact_id; - } - /* - end security verification - */ + if ( isset( $settings['customersfiles'] ) && is_array( $settings['customersfiles'] ) && count( $settings['customersfiles'] ) > 0 ) { + foreach ( $settings['customersfiles'] as $cfb ) { + $thisFileSlotName = ''; + if ( isset( $cfb[0] ) ) { + $thisFileSlotName = $cfb[0]; + } + $filePerma = ''; if ( isset( $thisFileSlotName ) && ! empty( $thisFileSlotName ) ) { - if(!empty($_FILES['zbsc_file_'.$cfSubKey]['name']) && - (!isset($zbsc_justUploadedCustomer) || - (isset($zbsc_justUploadedCustomer) && $zbsc_justUploadedCustomer != $_FILES['zbsc_file_'.$cfSubKey]['name']) - ) - ) { + // $filePerma = strtolower(str_replace(' ','_',str_replace('.','_',substr($thisFileSlotName,0,20)))); + $filePerma = $zbs->DAL->makeSlug( $thisFileSlotName ); - // Blocking repeat-upload bug - $zbsc_justUploadedCustomer = $_FILES['zbsc_file_'.$cfSubKey]['name']; - - // verify file extension and mime type - if ( jpcrm_file_check_mime_extension( $_FILES['zbsc_file_'.$cfSubKey] ) ){ - - $upload = wp_upload_bits($_FILES['zbsc_file_'.$cfSubKey]['name'], null, file_get_contents($_FILES['zbsc_file_'.$cfSubKey]['tmp_name'])); + } - if ( isset( $upload['error'] ) && $upload['error'] != 0 ) { - wp_die('There was an error uploading your file. The error is: ' . esc_html( $upload['error'] ) ); - } else { - //update_post_meta($contact_id, 'zbsc_file_'.$cfSubKey, $upload); + if ( ! empty( $thisFileSlotName ) && ! empty( $filePerma ) ) { + $cfbsubs[ $filePerma ] = $thisFileSlotName; + } + } + } - // v2.13 - also privatise the file (move to our asset store) - // $upload will have 'file' and 'url' - $fileName = basename($upload['file']); - $fileDir = dirname($upload['file']); - $privateThatFile = zeroBSCRM_privatiseUploadedFile($fileDir,$fileName); - if (is_array($privateThatFile) && isset($privateThatFile['file'])){ + if ( count( $cfbsubs ) > 0 ) { + foreach ( $cfbsubs as $cfSubKey => $cfSubName ) { - // successfully moved to our store + /* --- security verification --- */ + if ( isset( $_POST['zbsc_file_attachment_nonce'] ) ) { + if ( ! wp_verify_nonce( $_POST['zbsc_file_attachment_nonce'], plugin_basename( __FILE__ ) ) ) { + return $contact_id; + } // end if + } - // modify URL + file attributes - $upload['file'] = $privateThatFile['file']; - $upload['url'] = $privateThatFile['url']; + if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { + return $contact_id; + } // end if - // add this extra identifier if in privatised sys - $upload['priv'] = true; + if ( ! zeroBSCRM_permsCustomers() ) { + return $contact_id; + } + /* - end security verification - */ - } else { + if ( ! empty( $_FILES[ 'zbsc_file_' . $cfSubKey ]['name'] ) && + ( ! isset( $zbsc_justUploadedCustomer ) || + ( isset( $zbsc_justUploadedCustomer ) && $zbsc_justUploadedCustomer != $_FILES[ 'zbsc_file_' . $cfSubKey ]['name'] ) + ) + ) { - // couldn't move to store, leave in uploaded for now :) + // Blocking repeat-upload bug + $zbsc_justUploadedCustomer = $_FILES[ 'zbsc_file_' . $cfSubKey ]['name']; - } + // verify file extension and mime type + if ( jpcrm_file_check_mime_extension( $_FILES[ 'zbsc_file_' . $cfSubKey ] ) ) { + $upload = wp_upload_bits( $_FILES[ 'zbsc_file_' . $cfSubKey ]['name'], null, file_get_contents( $_FILES[ 'zbsc_file_' . $cfSubKey ]['tmp_name'] ) ); - // w mod - adds to array :) - $zbsCustomerFiles = zeroBSCRM_getCustomerFiles($contact_id); + if ( isset( $upload['error'] ) && $upload['error'] != 0 ) { + wp_die( 'There was an error uploading your file. The error is: ' . esc_html( $upload['error'] ) ); + } else { + // update_post_meta($contact_id, 'zbsc_file_'.$cfSubKey, $upload); - if (is_array($zbsCustomerFiles)){ + // v2.13 - also privatise the file (move to our asset store) + // $upload will have 'file' and 'url' + $fileName = basename( $upload['file'] ); + $fileDir = dirname( $upload['file'] ); + $privateThatFile = zeroBSCRM_privatiseUploadedFile( $fileDir, $fileName ); + if ( is_array( $privateThatFile ) && isset( $privateThatFile['file'] ) ) { - //add it - $zbsCustomerFiles[] = $upload; + // successfully moved to our store - } else { + // modify URL + file attributes + $upload['file'] = $privateThatFile['file']; + $upload['url'] = $privateThatFile['url']; - // first - $zbsCustomerFiles = array($upload); + // add this extra identifier if in privatised sys + $upload['priv'] = true; - } + } else { - ///update_post_meta($contact_id, 'zbs_customer_files', $zbsCustomerFiles); - zeroBSCRM_updateCustomerFiles($contact_id,$zbsCustomerFiles); + // couldn't move to store, leave in uploaded for now :) - // this'll override any prev in that slot, too - zeroBSCRM_fileslots_addToSlot($cfSubKey,$upload['file'],$contact_id,ZBS_TYPE_CONTACT,true); + } - // Fire any 'post-upload-processing' (e.g. CPP makes thumbnails of pdf, jpg, etc.) - do_action('zbs_post_upload_contact',$upload); - } - } else { - wp_die("The file type that you've uploaded is not an accepted file format."); - } + // w mod - adds to array :) + $zbsCustomerFiles = zeroBSCRM_getCustomerFiles( $contact_id ); - } // if file + if ( is_array( $zbsCustomerFiles ) ) { - } /// / foreach + // add it + $zbsCustomerFiles[] = $upload; + } else { - } + // first + $zbsCustomerFiles = array( $upload ); - return $contact; - } - } + } + // update_post_meta($contact_id, 'zbs_customer_files', $zbsCustomerFiles); + zeroBSCRM_updateCustomerFiles( $contact_id, $zbsCustomerFiles ); -/* ====================================================== - / Attach (custom) fileboxes to customer metabox - ====================================================== */ + // this'll override any prev in that slot, too + zeroBSCRM_fileslots_addToSlot( $cfSubKey, $upload['file'], $contact_id, ZBS_TYPE_CONTACT, true ); -/* ====================================================== - Attach files to customer metabox - ====================================================== */ + // Fire any 'post-upload-processing' (e.g. CPP makes thumbnails of pdf, jpg, etc.) + do_action( 'zbs_post_upload_contact', $upload ); + } + } else { + wp_die( "The file type that you've uploaded is not an accepted file format." ); + } + } // if file + } /// / foreach + } + } -/* ====================================================== - Contact Files Metabox - ====================================================== */ + return $contact; + } +} - class zeroBS__Metabox_ContactFiles extends zeroBS__Metabox{ +/* +====================================================== + / Attach (custom) fileboxes to customer metabox + ====================================================== */ - public function __construct( $plugin_file ) { +/* +====================================================== + Attach files to customer metabox + ====================================================== */ - $this->objType = 'contact'; - $this->metaboxID = 'zerobs-customer-files'; - $this->metaboxTitle = __('Other Files',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->capabilities = array( +/* +====================================================== + Contact Files Metabox + ====================================================== */ - 'can_hide' => true, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => true, // can be added as tab - 'can_minimise' => true // can be minimised +class zeroBS__Metabox_ContactFiles extends zeroBS__Metabox { - ); + public function __construct( $plugin_file ) { - // call this - $this->initMetabox(); + $this->objType = 'contact'; + $this->metaboxID = 'zerobs-customer-files'; + $this->metaboxTitle = __( 'Other Files', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'low'; + $this->capabilities = array( - } + 'can_hide' => true, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => true, // can be added as tab + 'can_minimise' => true, // can be minimised - public function html( $contact, $metabox ) { + ); - global $zbs; + // call this + $this->initMetabox(); + } - $html = ''; + public function html( $contact, $metabox ) { - // wmod + global $zbs; - #} retrieve - shouldn't these vars be "other files"... confusing - $zbsFiles = false; - if (isset($contact['id'])) $zbsFiles = zeroBSCRM_getCustomerFiles($contact['id']); + $html = ''; - ?> + // wmod - +
+ + 0 ) { + ?> + + + 0){ - ?> -
+ + + + + + + + slugs['editfile'] ) . '&customer=' . $contact['id'] . '&fileid=' . ( $fileLineIndx - 1 ); + + echo ''; + echo ''; + echo ''; + ++$fileLineIndx; + + } + ?> +
'; + + // if using portal.. state shown/hidden + // this is also shown in each file slot :) if you change any of it change that too + if ( defined( 'ZBS_CLIENTPRO_TEMPLATES' ) ) { + if ( isset( $zbsFile['portal'] ) && $zbsFile['portal'] ) { + echo "

" . esc_html__( 'Shown on Portal', 'zero-bs-crm' ) . '

'; + } else { + echo "

" . esc_html__( 'Not shown on Portal', 'zero-bs-crm' ) . '

'; + } + } + + echo '
' . esc_html__( 'Delete', 'zero-bs-crm' ) . ' ' . esc_html__( 'Edit', 'zero-bs-crm' ) . '
+
- - - - - - - - - /* $file = basename($zbsFile['file']); + '; - $file = substr($file,strpos($file, '-')+1); - } */ - $file = zeroBSCRM_files_baseName($zbsFile['file'],isset($zbsFile['priv'])); + ?> + + - $fileEditUrl = admin_url('admin.php?page='.$zbs->slugs['editfile']) . "&customer=".$contact['id']."&fileid=" . ($fileLineIndx-1); + +

()
:
+ +
+ '; - echo '
'; + // PerfTest: zeroBSCRM_performanceTest_finishTimer('custmetabox'); + // PerfTest: zeroBSCRM_performanceTest_debugOut(); - // if using portal.. state shown/hidden - // this is also shown in each file slot :) if you change any of it change that too - if(defined('ZBS_CLIENTPRO_TEMPLATES')){ - if(isset($zbsFile['portal']) && $zbsFile['portal']){ - echo "

".esc_html__('Shown on Portal','zero-bs-crm').'

'; - }else{ - echo "

".esc_html__('Not shown on Portal','zero-bs-crm').'

'; - } - } + ?> + + objType = 'contact'; + $this->metaboxID = 'zerobs-customer-portal'; + $this->metaboxTitle = __( 'Client Portal', 'zero-bs-crm' ); + $this->metaboxScreen = $metabox_screen; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->capabilities = array( - // w mod - adds to array :) - $zbsCustomerFiles = zeroBSCRM_getCustomerFiles($contact_id); + 'can_hide' => true, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised - if (is_array($zbsCustomerFiles)){ + ); - //add it - $zbsCustomerFiles[] = $upload; + // call this + $this->initMetabox(); + } - } else { + public function html( $contact, $metabox ) { - // first - $zbsCustomerFiles = array($upload); + // PerfTest: zeroBSCRM_performanceTest_startTimer('portal-draw'); - } + global $plugin_page, $zbs; + $screen = get_current_screen(); - ///update_post_meta($id, 'zbs_customer_files', $zbsCustomerFiles); - zeroBSCRM_updateCustomerFiles($contact_id,$zbsCustomerFiles); + $wp_user_id = ''; + #} Rather than reload all the time :) + global $zbsContactEditing; - // Fire any 'post-upload-processing' (e.g. CPP makes thumbnails of pdf, jpg, etc.) - do_action('zbs_post_upload_contact',$upload); - } - } else { - wp_die("The file type that you've uploaded is not an accepted file format."); - } - } + #} retrieve + // $zbsCustomer = get_post_meta($contact['id'], 'zbs_customer_meta', true); + if ( ! isset( $zbsContactEditing ) && isset( $contact['id'] ) ) { + $zbsCustomer = zeroBS_getCustomer( $contact['id'], false, false, false ); + $zbsContactEditing = $zbsCustomer; + } else { + $zbsCustomer = $zbsContactEditing; + } - return $contact; - } - } + if ( isset( $zbsCustomer ) && is_array( $zbsCustomer ) && isset( $zbsCustomer['email'] ) ) { + // check customer link to see if it exists - wh moved to dal + $wp_user_id = zeroBSCRM_getClientPortalUserID( $contact['id'] ); -/* ====================================================== - / Attach files to customer metabox - ====================================================== */ + /* + nope + if($wp_user_id == ''){ + $wp_user_id = email_exists( $zbsCustomer['email'] ); + } */ + } + echo '
'; -/* ====================================================== - Create Client Portal - ====================================================== */ + // get user obj + $user_object = get_userdata( $wp_user_id ); -class zeroBS__Metabox_ContactPortal extends zeroBS__Metabox{ + if ( $user_object ) { - public function __construct( $plugin_file, $metabox_screen = 'zbs-add-edit-contact-edit' ) { + // a user already exists with this email - $this->objType = 'contact'; - $this->metaboxID = 'zerobs-customer-portal'; - $this->metaboxTitle = __('Client Portal',"zero-bs-crm"); - $this->metaboxScreen = $metabox_screen; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->capabilities = array( + echo '
'; - 'can_hide' => true, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true // can be minimised + esc_html_e( 'WordPress User Linked', 'zero-bs-crm' ); + echo ' #' . esc_html( $wp_user_id ) . ':
'; - ); + echo '' . esc_html( $user_object->user_email ) . ''; - // call this - $this->initMetabox(); + // wp admins get link + if ( zeroBSCRM_isWPAdmin() ) { - } + $url = admin_url( 'user-edit.php?user_id=' . $wp_user_id ); + echo '
' . esc_html__( 'View WordPress Profile', 'zero-bs-crm' ) . ''; // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText - public function html( $contact, $metabox ) { + } - // PerfTest: zeroBSCRM_performanceTest_startTimer('portal-draw'); + echo '
'; - global $plugin_page, $zbs; - $screen = get_current_screen(); - - $wp_user_id = ''; - #} Rather than reload all the time :) - global $zbsContactEditing; + // user ID will now have access to this area.. + echo '
'; - #} retrieve - //$zbsCustomer = get_post_meta($contact['id'], 'zbs_customer_meta', true); - if (!isset($zbsContactEditing) && isset($contact['id'])){ - $zbsCustomer = zeroBS_getCustomer($contact['id'],false,false,false); - $zbsContactEditing = $zbsCustomer; - } else { - $zbsCustomer = $zbsContactEditing; - } + echo esc_html( __( 'Client Portal Access:', 'zero-bs-crm' ) ); + $customerPortalActive = true; + if ( zeroBSCRM_isCustomerPortalDisabled( $contact['id'] ) ) { + $customerPortalActive = false; + } - if ( isset($zbsCustomer) && is_array($zbsCustomer) && isset($zbsCustomer['email']) ){ + if ( $customerPortalActive ) { - //check customer link to see if it exists - wh moved to dal - $wp_user_id = zeroBSCRM_getClientPortalUserID( $contact['id'] ); + // revoke/disable access + echo ' ' . esc_html( __( 'Enabled', 'zero-bs-crm' ) ) . ''; - /* nope - if($wp_user_id == ''){ - $wp_user_id = email_exists( $zbsCustomer['email'] ); - } */ - } + // wp admins get reset link, unless the crm contact is assigned to any other role than CRM Customer + if ( zeroBSCRM_isWPAdmin() && jpcrm_role_check( $user_object, array(), array(), array( 'zerobs_customer' ) ) ) { - echo '
'; + echo '
'; - // get user obj - $user_object = get_userdata( $wp_user_id ); + echo ''; - if ( $user_object ){ + echo ''; - // a user already exists with this email + echo '
'; - echo '
'; + } else { - esc_html_e('WordPress User Linked',"zero-bs-crm"); - echo ' #'. esc_html( $wp_user_id ) .':
'; + // explainer - rarely shown + echo '

' . esc_html__( 'The WordPress user has a role other than CRM Contact. They will need to reset their password via the WP login page.', 'zero-bs-crm' ) . '

'; - echo ''. esc_html( $user_object->user_email ) .''; + } - // wp admins get link - if ( zeroBSCRM_isWPAdmin() ){ - - $url = admin_url('user-edit.php?user_id='.$wp_user_id); - echo '
' . esc_html__( 'View WordPress Profile', 'zero-bs-crm' ) . ''; // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText + echo '
'; + printf( '%s', esc_url( zeroBS_portal_link() ), esc_html( __( 'Preview Portal', 'zero-bs-crm' ) ) ); + echo '
'; + } else { - } + // enable access + echo ' ' . esc_html( __( 'Disabled', 'zero-bs-crm' ) ) . ''; + // wp admins get enable link, unless the crm contact is assigned to any other role than CRM Customer + if ( zeroBSCRM_isWPAdmin() && jpcrm_role_check( $user_object, array(), array(), array( 'zerobs_customer' ) ) ) { - echo '
'; - - // user ID will now have access to this area.. - echo '
'; + echo '
'; + echo ''; + echo '
'; - echo esc_html( __( 'Client Portal Access:', 'zero-bs-crm' ) ); + } + } + echo ''; - $customerPortalActive = true; if (zeroBSCRM_isCustomerPortalDisabled($contact['id'])) $customerPortalActive = false; - - if ( $customerPortalActive ) { + echo '
'; - // revoke/disable access - echo ' ' . esc_html( __( 'Enabled', 'zero-bs-crm' ) ) . ''; + } elseif ( is_array( $zbsCustomer ) && isset( $zbsCustomer['email'] ) && ! empty( $zbsCustomer['email'] ) ) { + echo '
'; + echo esc_html( __( 'No WordPress User exists with this email', 'zero-bs-crm' ) ); + echo '

'; + echo '
'; + echo esc_html( __( 'Generate WordPress User', 'zero-bs-crm' ) ); + echo '
'; + echo ''; + echo '
'; + } else { + echo esc_html( __( 'Save your contact, or add an email to enable Client Portal functionality', 'zero-bs-crm' ) ); + } - // wp admins get reset link, unless the crm contact is assigned to any other role than CRM Customer - if ( zeroBSCRM_isWPAdmin() && jpcrm_role_check( $user_object, array(), array(), array( 'zerobs_customer' ) ) ) { + echo '
'; - echo '
'; + ?> + + '; - echo ''; - echo '
'; +/* +====================================================== + / Create Client Portal + ====================================================== */ - } +/* +====================================================== + Create Social Box + ====================================================== */ - } +class zeroBS__Metabox_ContactSocial extends zeroBS__Metabox { - echo ''; - + public function __construct( $plugin_file ) { - echo '
'; + $this->objType = 'contact'; + $this->metaboxID = 'zerobs-customer-social'; + $this->metaboxTitle = __( 'Social Profiles', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->capabilities = array( - } else if ( is_array($zbsCustomer) && isset($zbsCustomer['email']) && !empty($zbsCustomer['email'])){ - echo '
'; - echo esc_html( __( 'No WordPress User exists with this email', 'zero-bs-crm' ) ); - echo '

'; - echo '
'; - echo esc_html( __( 'Generate WordPress User', 'zero-bs-crm' ) ); - echo '
'; - echo ''; - echo '
'; - }else{ - echo esc_html( __( 'Save your contact, or add an email to enable Client Portal functionality', 'zero-bs-crm' ) ); - } - - echo '
'; - - ?> true, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + ); + // call this + $this->initMetabox(); + } -/* ====================================================== - / Create Client Portal - ====================================================== */ + public function html( $contact, $metabox ) { + global $plugin_page, $zbs; -/* ====================================================== - Create Social Box - ====================================================== */ + // declare + load existing + global $zbsSocialAccountTypes; + $zbsSocials = false; + if ( isset( $contact['id'] ) ) { + $zbsSocials = $zbs->DAL->contacts->getContactSocials( $contact['id'] ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + } -class zeroBS__Metabox_ContactSocial extends zeroBS__Metabox{ + if ( count( $zbsSocialAccountTypes ) > 0 ) { + foreach ( $zbsSocialAccountTypes as $socialKey => $socialAccType ) { + + ?> +
+ + + + + + +
+ objType = 'contact'; - $this->metaboxID = 'zerobs-customer-social'; - $this->metaboxTitle = __('Social Profiles',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->capabilities = array( + // ++ get counts etc. + } - 'can_hide' => true, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true // can be minimised + public function save_data( $contact_id, $contact ) { - ); + $zbsSocials = array(); - // call this - $this->initMetabox(); + global $zbsSocialAccountTypes; + foreach ( $zbsSocialAccountTypes as $socialKey => $socialAccType ) { - } + // set + $zbsSocials[ $socialKey ] = false; - public function html( $contact, $metabox ) { + // get from post if present + if ( isset( $_POST[ 'zbs-social-' . $socialAccType['slug'] ] ) && ! empty( $_POST[ 'zbs-social-' . $socialAccType['slug'] ] ) ) { + $zbsSocials[ $socialKey ] = sanitize_text_field( $_POST[ 'zbs-social-' . $socialAccType['slug'] ] ); + } + } - global $plugin_page, $zbs; + zeroBS_updateCustomerSocialAccounts( $contact_id, $zbsSocials ); - // declare + load existing - global $zbsSocialAccountTypes; - $zbsSocials = false; - if ( isset( $contact['id'] ) ) { - $zbsSocials = $zbs->DAL->contacts->getContactSocials( $contact['id'] ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase,WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - } + return $contact; + } +} - if (count($zbsSocialAccountTypes) > 0) foreach ($zbsSocialAccountTypes as $socialKey => $socialAccType){ +/* +====================================================== + / Create Social Box + ====================================================== */ - ?>
- - "> - - - - -
objType = 'contact'; + $this->metaboxID = 'zerobs-customer-aka'; + $this->metaboxTitle = __( 'Contact Aliases (AKA)', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'low'; + $this->capabilities = array( - // ++ get counts etc. + 'can_hide' => true, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised - } + ); - public function save_data( $contact_id, $contact ) { + // call this + $this->initMetabox(); + } - $zbsSocials = array(); - - global $zbsSocialAccountTypes; - foreach ($zbsSocialAccountTypes as $socialKey => $socialAccType){ + public function html( $contact, $metabox ) { - // set - $zbsSocials[$socialKey] = false; + global $plugin_page, $zbs; + $screen = get_current_screen(); + ?> + + +
+ +
+ 0 ) { + foreach ( $customerAliases as $alias ) { + ?> +
+
+
+ objType = 'contact'; - $this->metaboxID = 'zerobs-customer-aka'; - $this->metaboxTitle = __('Contact Aliases (AKA)',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'low'; - $this->capabilities = array( + } + } - 'can_hide' => true, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true // can be minimised + ?> +
+ + + +
- ); + + 0) echo esc_html( $contact['id'] ); else echo -1; ?>, - 'akaid': akaID, - 'sec': window.zbscrmjs_secToken - }; + } // / if cust defined + } +} - // Send it Pat :D - jQuery.ajax({ - type: "POST", - url: ajaxurl, // admin side is just ajaxurl not wptbpAJAX.ajaxurl, - "data": data, - dataType: 'json', - timeout: 20000, - success: function(response) { +/* +====================================================== + / Create AKA Box + ====================================================== */ - if (typeof response.res != "undefined"){ +/* +====================================================== + Create Tags Box + ====================================================== */ - console.log('removed:',response); +class zeroBS__Metabox_ContactTags extends zeroBS__Metabox_Tags { - var lID = akaID; + public function __construct( $plugin_file ) { - // remove from ui - jQuery('#zbs-aka-alias-' + lID).remove(); + $this->objTypeID = ZBS_TYPE_CONTACT; + $this->objType = 'contact'; + $this->metaboxID = 'zerobs-customer-tags'; + $this->metaboxTitle = __( 'Contact Tags', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->showSuggestions = true; + $this->capabilities = array( - //unblock - window.zbsAliasAKABlocker = false; - jQuery('#zbs-aka-alias-loader').hide(); + 'can_hide' => true, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised - } else { + ); - // err - swal( - '', - '', - 'warning' - ); - //unblock - window.zbsAliasAKABlocker = false; - jQuery('#zbs-aka-alias-loader').hide(); - } + // call this + $this->initMetabox(); + } - }, - error: function(response){ + // html + save dealt with by parent class :) +} - // err - swal( - '', - '', - 'warning' - ); - //unblock - window.zbsAliasAKABlocker = false; - jQuery('#zbs-aka-alias-loader').hide(); +/* +====================================================== + / Create Tags Box + ====================================================== */ - } +/* +====================================================== + Create Logs Box + ====================================================== */ - }); +class zeroBS__Metabox_ContactLogs extends zeroBS__Metabox_LogsV2 { + public function __construct( $plugin_file ) { - } // / akai id present + $this->objtypeid = ZBS_TYPE_CONTACT; - } + $this->objType = 'contact'; + $this->metaboxID = 'zerobs-customer-logs'; + $this->metaboxTitle = __( 'Activity Log', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'high'; + $this->capabilities = array( - }); - } + 'can_hide' => true, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => true, // can be added as tab + 'can_minimise' => true, // can be minimised + 'hide_on_new' => true, // no point in adding logs while adding contact, add after creation :) - - initMetabox(); + } - } + // html + save dealt with by parent class :) } -/* ====================================================== - / Create AKA Box - ====================================================== */ +/* +====================================================== + / Create Logs Box + ====================================================== */ +/* +====================================================== + "Contacts at Company" Metabox + ====================================================== */ -/* ====================================================== - Create Tags Box - ====================================================== */ +class zeroBS__Metabox_ContactCompany extends zeroBS__Metabox { -class zeroBS__Metabox_ContactTags extends zeroBS__Metabox_Tags{ + public function __construct( $plugin_file ) { + # (language switch) + $companyOrOrg = zeroBSCRM_getSetting( 'coororg' ); + $companyLabel = jpcrm_label_company(); - public function __construct( $plugin_file ) { - - $this->objTypeID = ZBS_TYPE_CONTACT; - $this->objType = 'contact'; - $this->metaboxID = 'zerobs-customer-tags'; - $this->metaboxTitle = __('Contact Tags',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->showSuggestions = true; - $this->capabilities = array( + $this->objType = 'contact'; + $this->metaboxID = 'zerobs-customer-company'; + $this->metaboxTitle = __( $companyLabel, 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'core'; + $this->capabilities = array( - 'can_hide' => true, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true // can be minimised + 'can_hide' => true, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised - ); + ); - // call this - $this->initMetabox(); + // call this + $this->initMetabox(); + } - } + public function html( $contact, $metabox ) { - // html + save dealt with by parent class :) -} + global $plugin_page, $zbs; -/* ====================================================== - / Create Tags Box - ====================================================== */ + // PerfTest: zeroBSCRM_performanceTest_startTimer('companydropdown'); -/* ====================================================== - Create Logs Box - ====================================================== */ + # (language switch) + $companyOrOrg = zeroBSCRM_getSetting( 'coororg' ); + $companyLabel = jpcrm_label_company(); -class zeroBS__Metabox_ContactLogs extends zeroBS__Metabox_LogsV2{ + #} Typeahead instead + echo "
"; + echo '' . esc_html( sprintf( __( 'Type to assign %s', 'zero-bs-crm' ), jpcrm_label_company() ) ) . ''; + #} Co Name Default + $coName = ''; + $coID = ''; + if ( 'contact' == $this->objType ) { + $coID = -1; + if ( is_array( $contact ) && isset( $contact['id'] ) ) { + $coID = zeroBS_getCustomerCompanyID( $contact['id'] ); + } + if ( ! empty( $coID ) ) { + $co = zeroBS_getCompany( $coID ); - public function __construct( $plugin_file ) { - - $this->objtypeid = ZBS_TYPE_CONTACT; - - $this->objType = 'contact'; - $this->metaboxID = 'zerobs-customer-logs'; - $this->metaboxTitle = __('Activity Log',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'high'; - $this->capabilities = array( + // 3.0 + if ( isset( $co ) && isset( $co['name'] ) ) { + $coName = $co['name']; + } - 'can_hide' => true, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => true, // can be added as tab - 'can_minimise' => true, // can be minimised - 'hide_on_new' => true // no point in adding logs while adding contact, add after creation :) + // < 3.0 + if ( isset( $co ) && isset( $co['meta'] ) && isset( $co['meta']['coname'] ) ) { + $coName = $co['meta']['coname']; + } - ); + if ( empty( $coName ) && isset( $co['coname'] ) ) { + $coName = $co['coname']; + } + } + } - // call this - $this->initMetabox(); + #} Output - } + if ( get_option( 'permalink_structure' ) == '' ) { + echo "
" . esc_html__( 'You are using Plain Permalinks. Please set your permalinks to %postname% by visiting ', 'zero-bs-crm' ) . "" . esc_html__( 'here', 'zero-bs-crm' ) . '
'; + } else { + echo zeroBSCRM_CompanyTypeList( 'zbscrmjs_customer_setCompany', $coName, true, 'zbscrmjs_customer_changedCompany' ); + } + #} Hidden input (real input) & Callback func + ?> + + - public function html( $contact, $metabox ) { + +
+ "; - echo "" . esc_html( sprintf( __( 'Type to assign %s', 'zero-bs-crm' ), jpcrm_label_company() ) ) . ''; +/* +====================================================== + / "Contacts at Company" Metabox Related Funcs + ====================================================== */ - #} Co Name Default - $coName = ''; $coID = ''; - if ( 'contact' == $this->objType ){ - $coID = -1; if (is_array($contact) && isset($contact['id'])) $coID = zeroBS_getCustomerCompanyID($contact['id']); - if (!empty($coID)){ - $co = zeroBS_getCompany($coID); +/* +====================================================== + Contact Activity Metabox + ====================================================== */ +class zeroBS__Metabox_Contact_Activity extends zeroBS__Metabox { - // 3.0 - if (isset($co) && isset($co['name'])) $coName = $co['name']; + public function __construct( $plugin_file ) { - // < 3.0 - if (isset($co) && isset($co['meta']) && isset($co['meta']['coname'])) $coName = $co['meta']['coname']; + $this->metaboxID = 'zbs-contact-activity-metabox'; + $this->metaboxTitle = __( 'Activity', 'zero-bs-crm' ); + $this->metaboxIcon = 'heartbeat'; + $this->metaboxScreen = 'zbs-view-contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; - if (empty($coName) && isset($co['coname'])) $coName = $co['coname']; - - } - } - - #} Output + // call this + $this->initMetabox(); + } - if ( get_option('permalink_structure') == '' ){ - echo "
" . esc_html__('You are using Plain Permalinks. Please set your permalinks to %postname% by visiting ','zero-bs-crm') . "".esc_html__('here','zero-bs-crm')."
"; - }else{ - echo zeroBSCRM_CompanyTypeList('zbscrmjs_customer_setCompany',$coName,true,'zbscrmjs_customer_changedCompany'); - } - #} Hidden input (real input) & Callback func - ?> - + echo '
'; - -
'; + } + // DAL 2 saves type as permalinked + if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ] ) ) { + $logTitle .= __( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ]['label'], 'zero-bs-crm' ); + } - // PerfTest: zeroBSCRM_performanceTest_finishTimer('companydropdown'); - } + ?> + + +

+ +

+ + + +
+ acceptable_restricted_html ); ?> +
+ - public function save_data( $contact_id, $contact ) { - + - - -/* ====================================================== - Contact Activity Metabox - ====================================================== */ -class zeroBS__Metabox_Contact_Activity extends zeroBS__Metabox { + + metaboxID = 'zbs-contact-activity-metabox'; - $this->metaboxTitle = __('Activity', 'zero-bs-crm'); - $this->metaboxIcon = 'heartbeat'; - $this->metaboxScreen = 'zbs-view-contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - - // call this - $this->initMetabox(); + ++$pinned_log_count; - } + } + } - public function html( $obj, $metabox ) { - - global $zbs, $zeroBSCRM_logTypes; - - $objid = -1; if (is_array($obj) && isset($obj['id'])) $objid = $obj['id']; - - // output any pinned logs - $pinned_logs = $zbs->DAL->logs->getLogsForObj(array( - - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $objid, - 'only_pinned' => true, - 'incMeta' => true, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => -1, - 'perPage' => -1, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) - - )); - - if ( is_array( $pinned_logs ) && count( $pinned_logs ) > 0 ){ - - $pinned_log_count = 0; - - echo '

' . esc_attr__( 'Pinned Logs', 'zero-bs-crm' ) . '

'; - echo '
'; - foreach ( $pinned_logs as $log ){ - - if (is_array($log) && isset($log['created'])){ - - if ( $pinned_log_count > 0 ){ - - ?>
'; - - // ico? - $ico = ''; $logKey = strtolower(str_replace(' ','_',str_replace(':','_',$log['type']))); - if (isset($zeroBSCRM_logTypes['zerobs_customer'][$logKey])) $ico = $zeroBSCRM_logTypes['zerobs_customer'][$logKey]['ico']; - // these are FA ico's at this point - - // compile this first, so can catch default (empty types) - $logTitle = ''; - if (!empty($ico)) $logTitle .= ' '; - // DAL 2 saves type as permalinked - if (isset($zeroBSCRM_logTypes['zerobs_customer'][$logKey])) $logTitle .= __($zeroBSCRM_logTypes['zerobs_customer'][$logKey]['label'],"zero-bs-crm"); - - ?> - - -

- -

- - - -
- acceptable_restricted_html ); ?> -
- - - - -
+ + '; - echo '
'; - $zbsCustomerActivity = zeroBSCRM_getContactLogs($objid,true,100,0,'',false); - zeroBSCRM_html_contactTimeline($objid,$zbsCustomerActivity,$obj); - echo '
'; - echo ''; + // normal activity output + echo '
'; + echo '
'; + $zbsCustomerActivity = zeroBSCRM_getContactLogs( $objid, true, 100, 0, '', false ); + zeroBSCRM_html_contactTimeline( $objid, $zbsCustomerActivity, $obj ); + echo '
'; + echo '
'; + } - } - - // nothing to save here. - public function save_data( $objID, $obj ) { - return $obj; - } + // nothing to save here. + public function save_data( $objID, $obj ) { + return $obj; + } } - -/* ====================================================== - / Contact Activity Metabox - ====================================================== */ +/* +====================================================== + / Contact Activity Metabox + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.ExternalSources.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.ExternalSources.php index 8578eeb95f48..8967aa029d02 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.ExternalSources.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.ExternalSources.php @@ -1,5 +1,5 @@ -postType = 'zerobs_customer'; - $this->objType = 'contact'; - $this->objTypeID = ZBS_TYPE_CONTACT; - $this->metaboxID = 'zerobs-externalsource'; - $this->metaboxTitle = __('External Source',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // DEFAULT (overriden by metaboxScreens below) - // Better than this, is initiating multiple of this class with diff screens/objtypes - // ... because that presevers obj type unlike this solution: $this->metaboxScreens = array('zbs-add-edit-contact-edit','zbs-add-edit-company-edit'); // (since v3.0 we can add multiple, overrides metaboxScreen) - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'low'; - $this->saveOrder = 1; - $this->capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved - - ); - - // Catch any passed params as overrides - // (this allows us to have multiple initialised (e.g. one for contacts, one co's)) - if (isset($objType)) $this->objType = $objType; - if (isset($objType)) $this->objTypeID = $zbs->DAL->objTypeID($this->objType); - if (isset($metaboxScreen)) $this->metaboxScreen = $metaboxScreen; - - // set typeint based on type - $this->typeInt = $zbs->DAL->objTypeID($this->objType); // contact -> ZBS_TYPE_CONTACT = 1 - - #} Only load if is legit. - - // also hide if "new" (not edit) - as defies point of extsource - $isEdit = false; - if (isset($_GET['action']) && $_GET['action'] == 'edit' && isset($_GET['zbsid']) && !empty($_GET['zbsid'])) $isEdit = true; - - if (in_array($this->objType,$this->acceptableTypes) && $isEdit){ - // call this - $this->initMetabox(); - } - - } - - public function html( $obj, $metabox ) { - - global $zbs; - - // Only load if is legit. - if ( in_array( $this->objType, $this->acceptableTypes ) ){ - - $object_id = -1; if ( is_array( $obj ) && isset( $obj['id'] ) ) { - $object_id = (int)$obj['id']; - } - - // use centralised function to draw - jpcrm_render_external_sources_by_id( $object_id, $this->objTypeID ); - - } // / only load if post type - - } + public function __construct( $plugin_file, $objType = 'contact', $metaboxScreen = 'zbs-add-edit-contact-edit' ) { + + global $zbs; + + // set these + // DAL3 switched for objType $this->postType = 'zerobs_customer'; + $this->objType = 'contact'; + $this->objTypeID = ZBS_TYPE_CONTACT; + $this->metaboxID = 'zerobs-externalsource'; + $this->metaboxTitle = __( 'External Source', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-contact-edit'; // DEFAULT (overriden by metaboxScreens below) + // Better than this, is initiating multiple of this class with diff screens/objtypes + // ... because that presevers obj type unlike this solution: $this->metaboxScreens = array('zbs-add-edit-contact-edit','zbs-add-edit-company-edit'); // (since v3.0 we can add multiple, overrides metaboxScreen) + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'low'; + $this->saveOrder = 1; + $this->capabilities = array( + + 'can_hide' => false, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved + + ); + + // Catch any passed params as overrides + // (this allows us to have multiple initialised (e.g. one for contacts, one co's)) + if ( isset( $objType ) ) { + $this->objType = $objType; + } + if ( isset( $objType ) ) { + $this->objTypeID = $zbs->DAL->objTypeID( $this->objType ); + } + if ( isset( $metaboxScreen ) ) { + $this->metaboxScreen = $metaboxScreen; + } + + // set typeint based on type + $this->typeInt = $zbs->DAL->objTypeID( $this->objType ); // contact -> ZBS_TYPE_CONTACT = 1 + + #} Only load if is legit. + + // also hide if "new" (not edit) - as defies point of extsource + $isEdit = false; + if ( isset( $_GET['action'] ) && $_GET['action'] == 'edit' && isset( $_GET['zbsid'] ) && ! empty( $_GET['zbsid'] ) ) { + $isEdit = true; + } + + if ( in_array( $this->objType, $this->acceptableTypes ) && $isEdit ) { + // call this + $this->initMetabox(); + } + } + + public function html( $obj, $metabox ) { + + global $zbs; + + // Only load if is legit. + if ( in_array( $this->objType, $this->acceptableTypes ) ) { + + $object_id = -1; if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $object_id = (int) $obj['id']; + } + + // use centralised function to draw + jpcrm_render_external_sources_by_id( $object_id, $this->objTypeID ); + + } // / only load if post type + } } /** diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Forms.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Forms.php index 061d523fa380..cfa2a2239c9b 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Forms.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Forms.php @@ -1,5 +1,5 @@ -postType = 'zerobs_customer'; + $this->objType = 'form'; + $this->metaboxID = 'zerobs-form-edit'; + $this->metaboxTitle = __( 'Form Language Labels', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-form-edit'; + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( - // this is to save + edit $fieldPrefix = 'zbsf_'; - private $fieldPrefix = 'zbsf_'; + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - public function __construct( $plugin_file ) { + ); - // set these - // DAL3 switched for objType $this->postType = 'zerobs_customer'; - $this->objType = 'form'; - $this->metaboxID = 'zerobs-form-edit'; - $this->metaboxTitle = __('Form Language Labels','zero-bs-crm'); - $this->metaboxScreen = 'zbs-add-edit-form-edit'; - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( + // call this + $this->initMetabox(); + } - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved + public function html( $form, $metabox ) { - ); + // localise ID + $formID = -1; + if ( is_array( $form ) && isset( $form['id'] ) ) { + $formID = (int) $form['id']; + } - // call this - $this->initMetabox(); + // if new + $zbsObjDataPrefill passed, use that instead of loaded trans. + if ( $formID == -1 ) { + global $zbsObjDataPrefill; + $form = $zbsObjDataPrefill; + } - } + // fields + global $zbsFormFields; - public function html( $form, $metabox ) { - - // localise ID - $formID = -1; if (is_array($form) && isset($form['id'])) $formID = (int)$form['id']; - - // if new + $zbsObjDataPrefill passed, use that instead of loaded trans. - if ($formID == -1){ - global $zbsObjDataPrefill; - $form = $zbsObjDataPrefill; - } - - // fields - global $zbsFormFields; - - ?> + ?> - - - $fieldV){ - - #} Ignore no and date, dealt with above - switch ($fieldV[0]){ - - case 'text': - - ?> - -
- -
- -
-
'; - - define('ZBS_OBJ_SAVED',1); - - // DAL3.0+ - global $zbs; - - // check this - if (empty($form_id) || $form_id < 1) $form_id = -1; - - /* old way: - - global $zbsFormFields; - foreach ($zbsFormFields as $fK => $fV){ - $zbsFormFieldMeta[$fK] = ''; - if (isset($_POST['zbscf_'.$fK])) { - switch ($fV[0]){ - case 'text': - $zbsFormFieldMeta[$fK] = zeroBSCRM_textProcess($_POST['zbscf_'.$fK]); - break; - case 'textarea': - $zbsFormFieldMeta[$fK] = zeroBSCRM_textProcess($_POST['zbscf_'.$fK]); - break; - default: - $zbsFormFieldMeta[$fK] = sanitize_text_field($_POST['zbscf_'.$fK]); - break; - } - } - } - update_post_meta($post_id, 'zbs_form_field_meta', $zbsFormFieldMeta); - - */ - - // DAL3 way: - $autoGenAutonumbers = true; // generate if not set :) - $form = zeroBS_buildObjArr($_POST,array(),$this->fieldPrefix,'',false,ZBS_TYPE_FORM,$autoGenAutonumbers); - - // add/update - $addUpdateReturn = $zbs->DAL->forms->addUpdateForm(array( - - 'id' => $form_id, - 'data' => $form, - 'limitedFields' => -1, - - )); - - // Note: For NEW objs, we make sure a global is set here, that other update funcs can catch - // ... so it's essential this one runs first! - // this is managed in the metabox Class :) - if ($form_id == -1 && !empty($addUpdateReturn) && $addUpdateReturn != -1) { - - $form_id = $addUpdateReturn; - global $zbsJustInsertedMetaboxID; $zbsJustInsertedMetaboxID = $form_id; - - // set this so it redirs - $this->newRecordNeedsRedir = true; - } - - // success? - if ($addUpdateReturn != -1 && $addUpdateReturn > 0){ - - // Update Msg - // this adds an update message which'll go out ahead of any content - // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); - // This adds to edit page - $this->updateMessage(); - - // catch any non-critical messages - $nonCriticalMessages = $zbs->DAL->getErrors(ZBS_TYPE_FORM); - if (is_array($nonCriticalMessages) && count($nonCriticalMessages) > 0) $this->dalNoticeMessage($nonCriticalMessages); - - - } else { - - // fail somehow - $failMessages = $zbs->DAL->getErrors(ZBS_TYPE_FORM); - - // show msg (retrieved from DAL err stack) - if (is_array($failMessages) && count($failMessages) > 0) - $this->dalErrorMessage($failMessages); - else - $this->dalErrorMessage(array(__('Insert/Update Failed with general error','zero-bs-crm'))); - - // pass the pre-fill: - global $zbsObjDataPrefill; $zbsObjDataPrefill = $form; - - - } - - } - - return $form; - } - - // This catches 'new' contacts + redirs to right url - public function post_save_data($objID,$obj){ - - if ($this->newRecordNeedsRedir){ - - global $zbsJustInsertedMetaboxID; - if (!empty($zbsJustInsertedMetaboxID) && $zbsJustInsertedMetaboxID > 0){ - - // redir - wp_redirect( jpcrm_esc_link('edit',$zbsJustInsertedMetaboxID,$this->objType) ); + + + $fieldV ) { + + #} Ignore no and date, dealt with above + switch ( $fieldV[0] ) { + + case 'text': + ?> + + + + + + +
+ +
+ +
+
+ '; + + define( 'ZBS_OBJ_SAVED', 1 ); + + // DAL3.0+ + global $zbs; + + // check this + if ( empty( $form_id ) || $form_id < 1 ) { + $form_id = -1; + } + + /* + old way: + + global $zbsFormFields; + foreach ($zbsFormFields as $fK => $fV){ + $zbsFormFieldMeta[$fK] = ''; + if (isset($_POST['zbscf_'.$fK])) { + switch ($fV[0]){ + case 'text': + $zbsFormFieldMeta[$fK] = zeroBSCRM_textProcess($_POST['zbscf_'.$fK]); + break; + case 'textarea': + $zbsFormFieldMeta[$fK] = zeroBSCRM_textProcess($_POST['zbscf_'.$fK]); + break; + default: + $zbsFormFieldMeta[$fK] = sanitize_text_field($_POST['zbscf_'.$fK]); + break; + } + } + } + update_post_meta($post_id, 'zbs_form_field_meta', $zbsFormFieldMeta); + + */ + + // DAL3 way: + $autoGenAutonumbers = true; // generate if not set :) + $form = zeroBS_buildObjArr( $_POST, array(), $this->fieldPrefix, '', false, ZBS_TYPE_FORM, $autoGenAutonumbers ); + + // add/update + $addUpdateReturn = $zbs->DAL->forms->addUpdateForm( + array( + + 'id' => $form_id, + 'data' => $form, + 'limitedFields' => -1, + + ) + ); + + // Note: For NEW objs, we make sure a global is set here, that other update funcs can catch + // ... so it's essential this one runs first! + // this is managed in the metabox Class :) + if ( $form_id == -1 && ! empty( $addUpdateReturn ) && $addUpdateReturn != -1 ) { + + $form_id = $addUpdateReturn; + global $zbsJustInsertedMetaboxID; + $zbsJustInsertedMetaboxID = $form_id; + + // set this so it redirs + $this->newRecordNeedsRedir = true; + } + + // success? + if ( $addUpdateReturn != -1 && $addUpdateReturn > 0 ) { + + // Update Msg + // this adds an update message which'll go out ahead of any content + // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); + // This adds to edit page + $this->updateMessage(); + + // catch any non-critical messages + $nonCriticalMessages = $zbs->DAL->getErrors( ZBS_TYPE_FORM ); + if ( is_array( $nonCriticalMessages ) && count( $nonCriticalMessages ) > 0 ) { + $this->dalNoticeMessage( $nonCriticalMessages ); + } + } else { + + // fail somehow + $failMessages = $zbs->DAL->getErrors( ZBS_TYPE_FORM ); + + // show msg (retrieved from DAL err stack) + if ( is_array( $failMessages ) && count( $failMessages ) > 0 ) { + $this->dalErrorMessage( $failMessages ); + } else { + $this->dalErrorMessage( array( __( 'Insert/Update Failed with general error', 'zero-bs-crm' ) ) ); + } + + // pass the pre-fill: + global $zbsObjDataPrefill; + $zbsObjDataPrefill = $form; + + } + } + + return $form; + } + + // This catches 'new' contacts + redirs to right url + public function post_save_data( $objID, $obj ) { + + if ( $this->newRecordNeedsRedir ) { + + global $zbsJustInsertedMetaboxID; + if ( ! empty( $zbsJustInsertedMetaboxID ) && $zbsJustInsertedMetaboxID > 0 ) { + + // redir + wp_redirect( jpcrm_esc_link( 'edit', $zbsJustInsertedMetaboxID, $this->objType ) ); exit( 0 ); - } - - } - - } - - public function updateMessage(){ - - global $zbs; - - // zbs-not-urgent means it'll auto hide after 1.5s - // genericified from DAL3.0 - $msg = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',$zbs->DAL->typeStr($zbs->DAL->objTypeKey($this->objType)).' '.__('Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); - - $zbs->pageMessages[] = $msg; - - } - } - - -/* ====================================================== - / Forms v3 Language Metabox - ====================================================== */ - - -/* ====================================================== - Forms Settings v3 Metabox - ====================================================== */ - - class zeroBS__Metabox_FormSettings extends zeroBS__Metabox{ - - // this is for catching 'new' contacts - private $newRecordNeedsRedir = false; - - // this is to save + edit $fieldPrefix = 'zbsf_'; - private $fieldPrefix = 'zbsf_'; - - public function __construct( $plugin_file ) { - - // set these - // DAL3 switched for objType $this->postType = 'zerobs_customer'; - $this->objType = 'form'; - $this->metaboxID = 'zerobs-form-settings'; - $this->metaboxTitle = __('Form Settings','zero-bs-crm'); - $this->metaboxScreen = 'zbs-add-edit-form-edit'; - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved - - ); - - // call this - $this->initMetabox(); - - } - - public function html( $form, $metabox ) { - - // localise ID - $formID = -1; if (is_array($form) && isset($form['id'])) $formID = (int)$form['id']; - - //pre-processing - $formcss = ZEROBSCRM_URL . 'css/ZeroBSCRM.admin.frontform.css'; - $formjs = ZEROBSCRM_URL . 'js/ZeroBSCRM.leadform.js?ver=1.17'; - $formRoot = get_site_url().'/crmforms'; - - //$zbsfs = get_post_meta($formID,'zbs_form_style',true); - // DAL3+ saved in obj - $zbsfs = 'simple'; if (is_array($form) && isset($form['style'])) $zbsfs = $form['style']; - - // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - ?> - - -

-

-

.

-
+ } + } + } + + public function updateMessage() { + + global $zbs; + + // zbs-not-urgent means it'll auto hide after 1.5s + // genericified from DAL3.0 + $msg = zeroBSCRM_UI2_messageHTML( 'info olive mini zbs-not-urgent', $zbs->DAL->typeStr( $zbs->DAL->objTypeKey( $this->objType ) ) . ' ' . __( 'Updated', 'zero-bs-crm' ), '', 'address book outline', 'contactUpdated' ); + + $zbs->pageMessages[] = $msg; + } +} + +/* +====================================================== + / Forms v3 Language Metabox + ====================================================== */ + +/* +====================================================== + Forms Settings v3 Metabox + ====================================================== */ + +class zeroBS__Metabox_FormSettings extends zeroBS__Metabox { + + // this is for catching 'new' contacts + private $newRecordNeedsRedir = false; + + // this is to save + edit $fieldPrefix = 'zbsf_'; + private $fieldPrefix = 'zbsf_'; + + public function __construct( $plugin_file ) { + + // set these + // DAL3 switched for objType $this->postType = 'zerobs_customer'; + $this->objType = 'form'; + $this->metaboxID = 'zerobs-form-settings'; + $this->metaboxTitle = __( 'Form Settings', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-form-edit'; + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( + + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved + + ); + + // call this + $this->initMetabox(); + } + + public function html( $form, $metabox ) { + + // localise ID + $formID = -1; + if ( is_array( $form ) && isset( $form['id'] ) ) { + $formID = (int) $form['id']; + } + + // pre-processing + $formcss = ZEROBSCRM_URL . 'css/ZeroBSCRM.admin.frontform.css'; + $formjs = ZEROBSCRM_URL . 'js/ZeroBSCRM.leadform.js?ver=1.17'; + $formRoot = get_site_url() . '/crmforms'; + + // $zbsfs = get_post_meta($formID,'zbs_form_style',true); + // DAL3+ saved in obj + $zbsfs = 'simple'; + if ( is_array( $form ) && isset( $form['style'] ) ) { + $zbsfs = $form['style']; + } + + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + ?> + + +

+

+

.

+

-

0){ - - ?>[jetpackcrm_form id="" style=""]

-
- -
- -
-
-
-

Lorem Ipsum Text here

-

Lorem Ipsum s Text s here

-

Lorem Ipsum Text here

-

Lorem Ipsum Text here

-

Lorem Ipsum s Text s here

-

Lorem Ipsum Text here

-
-
-
-
-
-
-
-
-

Lorem Ipsum Text here

-

Lorem Ipsum s Text Lorem Ipsum m Ipsum s here

-

Lorem Ipsum Text here

-

Lorem Ipsum Text here

-

Lorem Ipsum s Text s here

-

Lorem Ipsum Text here

-
-
-
-
+

+ 0 ) { + + ?> + [jetpackcrm_form id="" style=""] + +

+
+ +
+ +
+
+
+

Lorem Ipsum Text here

+

Lorem Ipsum s Text s here

+

Lorem Ipsum Text here

+

Lorem Ipsum Text here

+

Lorem Ipsum s Text s here

+

Lorem Ipsum Text here

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

Lorem Ipsum Text here

+

Lorem Ipsum s Text Lorem Ipsum m Ipsum s here

+

Lorem Ipsum Text here

+

Lorem Ipsum Text here

+

Lorem Ipsum s Text s here

+

Lorem Ipsum Text here

+
+
+
+
'><iframe src='/naked/?fid=' height='200px' width='700px' style='border:0!important'></iframe> -
-
-
- -
-
-
-

Lorem Ipsum Text here

-
-
-

-

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

Lorem Ipsum s Text Lorem Ipsum m Ipsum s here

-
-
-
-
+
+
+
+ +
+
+
+

Lorem Ipsum Text here

+
+
+

+ +

+

+ +

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

Lorem Ipsum s Text Lorem Ipsum m Ipsum s here

+
+
+
+
'><iframe src='/content/?fid=' height='700px' width='700px' style='border:0!important'></iframe> -
-
- - -
- - -
-
-
-

Lorem Ipsum Text here

-

Lorem Ipsum s Text s here

-

Lorem Ipsum Text here

-
-
-

-

-
-
-
-
-
-
-
-
-

Lorem Ipsum Text here

-

Lorem Ipsum s Text Lorem Ipsum m Ipsum s here

-

Lorem Ipsum Text here

-
-
-
-
+
+
+ + +
+ + +
+
+
+

Lorem Ipsum Text here

+

Lorem Ipsum s Text s here

+

Lorem Ipsum Text here

+
+
+

+ +

+

+ +

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

Lorem Ipsum Text here

+

Lorem Ipsum s Text Lorem Ipsum m Ipsum s here

+

Lorem Ipsum Text here

+
+
+
+
'><iframe src='/simple/?fid=' height='300px' width='700px' style='border:0!important'></iframe> -
-
-
- +
+
+ + - - + + - -
ID,'zbs_form_style', $zbfs); - $zbs_form_conv = get_post_meta($post->ID, 'zbs_form_conversions', true); - $zbs_form_views = get_post_meta($post->ID, 'zbs_form_views', true); - if($zbs_form_conv == ''){ - update_post_meta($post->ID,'zbs_form_conversions',0); - } - if($zbs_form_views == ''){ - update_post_meta($post->ID,'zbs_form_views',0); - } - - .. V3 + nothing to do here, main langlabels box does save of style (zbs_form_style_post) - - */ - - return $form; - - } - } - - -/* ====================================================== - / Forms Settings v3 Metabox - ====================================================== */ - - - -/* ====================================================== - Forms embed v3 Metabox - ====================================================== */ - - class zeroBS__Metabox_FormEmbed extends zeroBS__Metabox{ - - public function __construct( $plugin_file ) { - - // set these - // DAL3 switched for objType $this->postType = 'zerobs_customer'; - $this->objType = 'form'; - $this->metaboxID = 'zerobs-form-embed'; - $this->metaboxTitle = __('Form Embedding','zero-bs-crm'); - $this->metaboxScreen = 'zbs-add-edit-form-edit'; - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->saveOrder = 1; - $this->capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved - - ); - - // call this - $this->initMetabox(); - - } - - public function html( $form, $metabox ) { - - global $zbs; + jQuery('.choice').off("click").on("click",function(e){ + + + jQuery('#zbs-form-pre').html(''); //clear out the HTML + var zbsf_pid = jQuery(this).data('pid'); + var zbsf_style = jQuery(this).data('style'); + + jQuery('#zbs_form_style_post').val(zbsf_style); + if(jQuery('#'+zbsf_style+'_html_form .form-wrapper').hasClass('zbs-form-wrap')){ + console.log('we have a form inside the wrapper'); + }else{ + ///not used? var zbsf_action = jQuery('#zbs_form_action').data('zbsformaction'); + jQuery('#'+zbsf_style+'_html_form .form-wrapper').wrap("
"); + jQuery('#'+zbsf_style+'_html_form .form-wrapper').addClass('zbs-form-wrap'); + } + + var zbsf_html = jQuery('#'+zbsf_style+'_html_form .zbs_form_content_wrap').html(); //replace with proper HTML form elements + // switched for proper global var ^ var zbsf_html_css_link = jQuery('.zbs_form_css').data('css'); + var zbsf_css_link = ""; + + //not used? var zbsf_html_js_link = jQuery('#zbs_form_js').data('js'); + //not used? console.log(zbsf_html_js_link); + var zbsf_js_link = " +
<script type='text/javascript' src=''></script>
+ postType = 'zerobs_customer'; + $this->objType = 'form'; + $this->metaboxID = 'zerobs-form-morefields'; + $this->metaboxTitle = __( 'Want More Fields?', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-form-edit'; + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'low'; + $this->saveOrder = 1; + $this->capabilities = array( + + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved + + ); + + ##WLREMOVE + $this->initMetabox(); + ##/WLREMOVE + } + + public function html( $form, $metabox ) { + + // this was in as js, wh converted for v3+ + $moreTitle = __( 'Need More Fields?', 'zero-bs-crm' ); + $moreDesc = __( 'Jetpack CRM forms cover simple use contact and subscription forms, but if you need more we suggest using a form plugin like Contact Form 7 or Gravity Forms:', 'zero-bs-crm' ) . ' ' . __( 'See Options', 'zero-bs-crm' ) . ''; + $moreFinal = '

' . $moreTitle . '

' . $moreDesc . '

'; + + echo $moreFinal; + } +} +/* +====================================================== + / Forms get more fields v3 Metabox + ====================================================== */ + +/* +====================================================== + Form Action Metabox + ====================================================== */ + +class zeroBS__Metabox_FormActions extends zeroBS__Metabox { + + public function __construct( $plugin_file ) { + + // set these + $this->objType = 'form'; + $this->metaboxID = 'zerobs-form-actions'; + $this->metaboxTitle = __( 'Form', 'zero-bs-crm' ) . ' ' . __( 'Actions', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-form-edit'; + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( + + 'can_hide' => false, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved + + ); + + // call this + $this->initMetabox(); + } + + public function html( $form, $metabox ) { + + ?> +
+ +
+ + 0 ) { // existing - // localise ID - $formID = -1; if (is_array($form) && isset($form['id'])) $formID = (int)$form['id']; - $zbsfs = 'simple'; if (is_array($form) && isset($form['style'])) $zbsfs = $form['style']; - - // get js url - $formjs = ZEROBSCRM_URL . 'js/ZeroBSCRM.leadform.js?ver=' . $zbs::VERSION; + ?> - ?>
-

-

-

-            
- -
<script type='text/javascript' src=''></script>
- postType = 'zerobs_customer'; - $this->objType = 'form'; - $this->metaboxID = 'zerobs-form-morefields'; - $this->metaboxTitle = __('Want More Fields?','zero-bs-crm'); - $this->metaboxScreen = 'zbs-add-edit-form-edit'; - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->saveOrder = 1; - $this->capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved - - ); - - ##WLREMOVE - $this->initMetabox(); - ##/WLREMOVE - - } - - public function html( $form, $metabox ) { - - // this was in as js, wh converted for v3+ - $moreTitle = __('Need More Fields?',"zero-bs-crm"); - $moreDesc = __('Jetpack CRM forms cover simple use contact and subscription forms, but if you need more we suggest using a form plugin like Contact Form 7 or Gravity Forms:',"zero-bs-crm").' '.__('See Options','zero-bs-crm').''; - $moreFinal = '

'.$moreTitle.'

'.$moreDesc.'

'; - - echo $moreFinal; - - } - } -/* ====================================================== - / Forms get more fields v3 Metabox - ====================================================== */ - - -/* ====================================================== - Form Action Metabox - ====================================================== */ - - class zeroBS__Metabox_FormActions extends zeroBS__Metabox{ - - public function __construct( $plugin_file ) { - - // set these - $this->objType = 'form'; - $this->metaboxID = 'zerobs-form-actions'; - $this->metaboxTitle = __('Form','zero-bs-crm').' '.__('Actions','zero-bs-crm'); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-form-edit'; - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved - - ); - - // call this - $this->initMetabox(); - - } - - public function html( $form, $metabox ) { - - ?>
- -
- - 0){ // existing - - ?> - -
+
-
- -
- - -
+ // delete? -
- +
+ +
+ + +
+
+ + // NEW form + ?> -
- +
+ -
+
-
+
+ objType = 'invoice'; - $this->metaboxID = 'zerobs-invoice-edit'; - $this->metaboxTitle = __( 'Invoice Information', 'zero-bs-crm' ); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-invoice-edit'; - $this->metaboxArea = 'normal'; + $this->objType = 'invoice'; + $this->metaboxID = 'zerobs-invoice-edit'; + $this->metaboxTitle = __( 'Invoice Information', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-invoice-edit'; + $this->metaboxArea = 'normal'; $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( + $this->saveOrder = 1; + $this->capabilities = array( 'can_hide' => false, // can be hidden 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently @@ -79,33 +83,32 @@ public function __construct( $plugin_file ) { // call this $this->initMetabox(); - } public function html( $invoice, $metabox ) { // localise ID - $invoiceID = is_array( $invoice ) && isset( $invoice['id'] ) ? (int)$invoice['id'] : -1; + $invoiceID = is_array( $invoice ) && isset( $invoice['id'] ) ? (int) $invoice['id'] : -1; global $zbs; // Prefill ID and OBJ are added to the #zbs_invoice to aid in prefilling the data (when drawn with JS) - $prefill_id = -1; - $prefill_obj = -1; + $prefill_id = -1; + $prefill_obj = -1; $prefill_email = ''; - $prefill_name = ''; + $prefill_name = ''; - if ( !empty( $_GET['zbsprefillcust'] ) ) { - $prefill_id = (int)$_GET['zbsprefillcust']; - $prefill_obj = ZBS_TYPE_CONTACT; + if ( ! empty( $_GET['zbsprefillcust'] ) ) { + $prefill_id = (int) $_GET['zbsprefillcust']; + $prefill_obj = ZBS_TYPE_CONTACT; $prefill_email = zeroBS_customerEmail( $prefill_id ); - $prefill_name = $zbs->DAL->contacts->getContactNameWithFallback( $prefill_id ); + $prefill_name = $zbs->DAL->contacts->getContactNameWithFallback( $prefill_id ); } - if ( !empty( $_GET['zbsprefillco'] ) ) { - $prefill_id = (int)$_GET['zbsprefillco']; - $prefill_obj = ZBS_TYPE_COMPANY; + if ( ! empty( $_GET['zbsprefillco'] ) ) { + $prefill_id = (int) $_GET['zbsprefillco']; + $prefill_obj = ZBS_TYPE_COMPANY; $prefill_email = zeroBS_companyEmail( $prefill_id ); - $prefill_name = $zbs->DAL->companies->getCompanyNameEtc( $prefill_id ); + $prefill_name = $zbs->DAL->companies->getCompanyNameEtc( $prefill_id ); } ?> @@ -126,7 +129,7 @@ public function html( $invoice, $metabox ) { // custom fields $customFields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_INVOICE ) ); - if ( !is_array( $customFields ) ) { + if ( ! is_array( $customFields ) ) { $customFields = array(); } @@ -170,7 +173,7 @@ public function html( $invoice, $metabox ) { public function save_data( $invoiceID, $invoice ) { - if ( !defined( 'ZBS_OBJ_SAVED' ) ) { + if ( ! defined( 'ZBS_OBJ_SAVED' ) ) { define( 'ZBS_OBJ_SAVED', 1 ); @@ -185,15 +188,15 @@ public function save_data( $invoiceID, $invoice ) { $existing_invoice = $zbs->DAL->invoices->getInvoice( $invoiceID ); $autoGenAutonumbers = true; // generate if not set :) - $removeEmpties = false; // req for autoGenAutonumbers - $invoice = zeroBS_buildObjArr( $_POST, array(), 'zbsi_', '', $removeEmpties, ZBS_TYPE_INVOICE, $autoGenAutonumbers ); + $removeEmpties = false; // req for autoGenAutonumbers + $invoice = zeroBS_buildObjArr( $_POST, array(), 'zbsi_', '', $removeEmpties, ZBS_TYPE_INVOICE, $autoGenAutonumbers ); // Use the tag-class function to retrieve any tags so we can add inline. // Save tags against objid $invoice['tags'] = zeroBSCRM_tags_retrieveFromPostBag( true, ZBS_TYPE_INVOICE ); // pay via - $invoice['pay_via'] = isset( $_POST['pay_via'] ) && (int)$_POST['pay_via'] === -1 ? -1 : 0; + $invoice['pay_via'] = isset( $_POST['pay_via'] ) && (int) $_POST['pay_via'] === -1 ? -1 : 0; // new way.. now not limited to 30 lines as now they are stored in [] type array in JS draw $zbsInvoiceLines = array(); @@ -204,18 +207,18 @@ public function save_data( $invoiceID, $invoice ) { $ks = sanitize_text_field( $k ); // at least this - if ( !isset( $zbsInvoiceLines[$ks]['net'] ) ) { - $zbsInvoiceLines[$ks]['net'] = 0.0; + if ( ! isset( $zbsInvoiceLines[ $ks ]['net'] ) ) { + $zbsInvoiceLines[ $ks ]['net'] = 0.0; } - $zbsInvoiceLines[$ks]['title'] = sanitize_text_field( $_POST['zbsli_itemname'][$k] ); - $zbsInvoiceLines[$ks]['desc'] = sanitize_textarea_field( $_POST['zbsli_itemdes'][$k] ); - $zbsInvoiceLines[$ks]['quantity'] = sanitize_text_field( $_POST['zbsli_quan'][$k] ); - $zbsInvoiceLines[$ks]['price'] = sanitize_text_field( $_POST['zbsli_price'][$k] ); + $zbsInvoiceLines[ $ks ]['title'] = sanitize_text_field( $_POST['zbsli_itemname'][ $k ] ); + $zbsInvoiceLines[ $ks ]['desc'] = sanitize_textarea_field( $_POST['zbsli_itemdes'][ $k ] ); + $zbsInvoiceLines[ $ks ]['quantity'] = sanitize_text_field( $_POST['zbsli_quan'][ $k ] ); + $zbsInvoiceLines[ $ks ]['price'] = sanitize_text_field( $_POST['zbsli_price'][ $k ] ); // calc a net, if have elements - if ( !empty( $zbsInvoiceLines[$ks]['quantity'] ) && !empty( $zbsInvoiceLines[$ks]['price'] ) ) { + if ( ! empty( $zbsInvoiceLines[ $ks ]['quantity'] ) && ! empty( $zbsInvoiceLines[ $ks ]['price'] ) ) { - $zbsInvoiceLines[$ks]['net'] = $zbsInvoiceLines[$ks]['quantity'] * $zbsInvoiceLines[$ks]['price']; + $zbsInvoiceLines[ $ks ]['net'] = $zbsInvoiceLines[ $ks ]['quantity'] * $zbsInvoiceLines[ $ks ]['price']; } else { @@ -224,10 +227,11 @@ public function save_data( $invoiceID, $invoice ) { } // taxes now stored as csv in 'taxes', 'tax' contains a total, but that's not passed by MS UI (yet? not needed?) - $zbsInvoiceLines[$ks]['tax'] = 0; - $zbsInvoiceLines[$ks]['taxes'] = empty( $_POST['zbsli_tax'][$k] ) ? '' : sanitize_text_field( $_POST['zbsli_tax'][$k] ); + $zbsInvoiceLines[ $ks ]['tax'] = 0; + $zbsInvoiceLines[ $ks ]['taxes'] = empty( $_POST['zbsli_tax'][ $k ] ) ? '' : sanitize_text_field( $_POST['zbsli_tax'][ $k ] ); - /* as at 22/2/19, each lineitem here could hold: + /* + as at 22/2/19, each lineitem here could hold: 'order' => '', 'title' => '', 'desc' => '', @@ -255,25 +259,25 @@ public function save_data( $invoiceID, $invoice ) { // other items to update // hours or quantity switch - if ( !empty( $_POST['invoice-customiser-type'] ) ) { + if ( ! empty( $_POST['invoice-customiser-type'] ) ) { $invoice['hours_or_quantity'] = $_POST['invoice-customiser-type'] === 'hours' ? 0 : 1; } // totals passed - $invoice['discount'] = empty( $_POST['invoice_discount_total'] ) ? 0 : (float)sanitize_text_field( $_POST['invoice_discount_total'] ); + $invoice['discount'] = empty( $_POST['invoice_discount_total'] ) ? 0 : (float) sanitize_text_field( $_POST['invoice_discount_total'] ); $invoice['discount_type'] = empty( $_POST['invoice_discount_type'] ) ? 0 : sanitize_text_field( $_POST['invoice_discount_type'] ); - $invoice['shipping'] = empty( $_POST['invoice_postage_total'] ) ? 0 : (float)sanitize_text_field( $_POST['invoice_postage_total'] ); + $invoice['shipping'] = empty( $_POST['invoice_postage_total'] ) ? 0 : (float) sanitize_text_field( $_POST['invoice_postage_total'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing $invoice['shipping_taxes'] = empty( $_POST['zbsli_tax_ship'] ) ? 0 : (float) sanitize_text_field( wp_unslash( $_POST['zbsli_tax_ship'] ) ); // or shipping_taxes (not set by MS script) // ... js pass through :o Will be overwritten on php calc on addUpdate, actually, v3.0+ - $invoice['total'] = empty( $_POST['zbs-inv-grand-total-store'] ) ? 0 : (float)sanitize_text_field( $_POST['zbs-inv-grand-total-store'] ); + $invoice['total'] = empty( $_POST['zbs-inv-grand-total-store'] ) ? 0 : (float) sanitize_text_field( $_POST['zbs-inv-grand-total-store'] ); // assignments - $zbsInvoiceContact = (int)$_POST['zbs_invoice_contact']; - $invoice['contacts'] = $zbsInvoiceContact > 0 ? array( $zbsInvoiceContact ) : array(); - $zbsInvoiceCompany = (int)$_POST['zbs_invoice_company']; + $zbsInvoiceContact = (int) $_POST['zbs_invoice_contact']; + $invoice['contacts'] = $zbsInvoiceContact > 0 ? array( $zbsInvoiceContact ) : array(); + $zbsInvoiceCompany = (int) $_POST['zbs_invoice_company']; $invoice['companies'] = $zbsInvoiceCompany > 0 ? array( $zbsInvoiceCompany ) : array(); // Later use: 'address_to_objtype' @@ -287,11 +291,11 @@ public function save_data( $invoiceID, $invoice ) { $ref_type = $zbs->settings->get( 'reftype' ); if ( $invoiceID === -1 && $ref_type === 'autonumber' ) { - $next_number = $zbs->settings->get( 'refnextnum' ); - $prefix = $zbs->settings->get( 'refprefix' ); - $suffix = $zbs->settings->get( 'refsuffix' ); + $next_number = $zbs->settings->get( 'refnextnum' ); + $prefix = $zbs->settings->get( 'refprefix' ); + $suffix = $zbs->settings->get( 'refsuffix' ); $invoice['id_override'] = $prefix . $next_number . $suffix; - $next_number++; + ++$next_number; $zbs->settings->update( 'refnextnum', $next_number ); } elseif ( isset( $_POST['zbsi_ref'] ) ) { $invoice['id_override'] = sanitize_text_field( $_POST['zbsi_ref'] ); @@ -304,7 +308,6 @@ public function save_data( $invoiceID, $invoice ) { $invoice['id_override'] = $existing_invoice['id_override']; } - } // this needs to be translated to UTS (GMT) @@ -328,7 +331,6 @@ public function save_data( $invoiceID, $invoice ) { $invoice['due_date'] = $invoice['date'] + ( $dueInDays * 60 * 60 * 24 ); } - } // ... this then catches datepicker-picked dates (if passed by datepicker variant to due_days) if ( isset( $_POST['zbsi_due_date'] ) ) { @@ -337,7 +339,8 @@ public function save_data( $invoiceID, $invoice ) { } // Custom Fields. - /*$customFields = $zbs->DAL->getActiveCustomFields(array('objtypeid' => ZBS_TYPE_INVOICE)); + /* + $customFields = $zbs->DAL->getActiveCustomFields(array('objtypeid' => ZBS_TYPE_INVOICE)); if (!is_array($customFields)) $customFields = array(); foreach ($customFields as $cfK => $cfV){ @@ -360,7 +363,7 @@ public function save_data( $invoiceID, $invoice ) { // Note: For NEW objs, we make sure a global is set here, that other update funcs can catch // ... so it's essential this one runs first! // this is managed in the metabox Class :) - if ( $invoiceID === -1 && !empty( $addUpdateReturn ) && $addUpdateReturn != -1 ) { + if ( $invoiceID === -1 && ! empty( $addUpdateReturn ) && $addUpdateReturn != -1 ) { $invoiceID = $addUpdateReturn; global $zbsJustInsertedMetaboxID; @@ -384,7 +387,6 @@ public function save_data( $invoiceID, $invoice ) { if ( is_array( $nonCriticalMessages ) && count( $nonCriticalMessages ) > 0 ) { $this->dalNoticeMessage( $nonCriticalMessages ); } - } else { // fail somehow @@ -402,7 +404,6 @@ public function save_data( $invoiceID, $invoice ) { $zbsObjDataPrefill = $invoice; } - } return $invoice; @@ -414,16 +415,14 @@ public function post_save_data( $objID, $obj ) { if ( $this->newRecordNeedsRedir ) { global $zbsJustInsertedMetaboxID; - if ( !empty( $zbsJustInsertedMetaboxID ) && $zbsJustInsertedMetaboxID > 0 ) { + if ( ! empty( $zbsJustInsertedMetaboxID ) && $zbsJustInsertedMetaboxID > 0 ) { // redir wp_redirect( jpcrm_esc_link( 'edit', $zbsJustInsertedMetaboxID, $this->objType ) ); exit( 0 ); } - } - } public function updateMessage() { @@ -435,420 +434,433 @@ public function updateMessage() { $msg = zeroBSCRM_UI2_messageHTML( 'info olive mini zbs-not-urgent', $zbs->DAL->typeStr( $zbs->DAL->objTypeKey( $this->objType ) ) . ' ' . __( 'Updated', 'zero-bs-crm' ), '', 'address book outline', 'contactUpdated' ); $zbs->pageMessages[] = $msg; - } } +/* +====================================================== + / Invoicing Metabox + ====================================================== */ -/* ====================================================== - / Invoicing Metabox - ====================================================== */ - - -/* ====================================================== - Invoice Files Metabox - ====================================================== */ +/* +====================================================== + Invoice Files Metabox + ====================================================== */ - class zeroBS__Metabox_InvoiceFiles extends zeroBS__Metabox{ +class zeroBS__Metabox_InvoiceFiles extends zeroBS__Metabox { - public function __construct( $plugin_file ) { - - // DAL3 switched for objType $this->postType = 'zerobs_customer'; - $this->objType = 'invoice'; - $this->metaboxID = 'zerobs-invoice-files'; - $this->metaboxTitle = __('Associated Files',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-invoice-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->capabilities = array( + public function __construct( $plugin_file ) { - 'can_hide' => true, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => true, // can be added as tab - 'can_minimise' => true // can be minimised + // DAL3 switched for objType $this->postType = 'zerobs_customer'; + $this->objType = 'invoice'; + $this->metaboxID = 'zerobs-invoice-files'; + $this->metaboxTitle = __( 'Associated Files', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-invoice-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'low'; + $this->capabilities = array( - ); + 'can_hide' => true, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => true, // can be added as tab + 'can_minimise' => true, // can be minimised - // call this - $this->initMetabox(); + ); - } + // call this + $this->initMetabox(); + } - public function html( $invoice, $metabox ) { + public function html( $invoice, $metabox ) { - global $zbs; + global $zbs; - $html = ''; + $html = ''; - // localise ID - $invoiceID = -1; if (is_array($invoice) && isset($invoice['id'])) $invoiceID = (int)$invoice['id']; + // localise ID + $invoiceID = -1; + if ( is_array( $invoice ) && isset( $invoice['id'] ) ) { + $invoiceID = (int) $invoice['id']; + } - #} retrieve - $zbsFiles = array(); if ($invoiceID > 0) $zbsFiles = zeroBSCRM_files_getFiles('invoice',$invoiceID); + #} retrieve + $zbsFiles = array(); + if ( $invoiceID > 0 ) { + $zbsFiles = zeroBSCRM_files_getFiles( 'invoice', $invoiceID ); + } - ?> + ?> +
- 0){ - ?> - + + + + } + ?> - '; + $html .= ''; - ?> - - -
- 0 ) { + ?> +
+ '. esc_html( $file ) .' ()'; - $fileLineIndx++; + echo ''; + ++$fileLineIndx; - } ?> -

()
:
- + objTypeID = ZBS_TYPE_INVOICE; - // DAL3 switched for objType $this->postType = 'zerobs_customer'; - $this->objType = 'invoice'; - $this->metaboxID = 'zerobs-invoice-tags'; - $this->metaboxTitle = __('Invoice Tags',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-invoice-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->showSuggestions = true; - $this->capabilities = array( + public function __construct( $plugin_file ) { - 'can_hide' => true, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true // can be minimised + $this->objTypeID = ZBS_TYPE_INVOICE; + // DAL3 switched for objType $this->postType = 'zerobs_customer'; + $this->objType = 'invoice'; + $this->metaboxID = 'zerobs-invoice-tags'; + $this->metaboxTitle = __( 'Invoice Tags', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-invoice-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->showSuggestions = true; + $this->capabilities = array( - ); + 'can_hide' => true, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised - // call this - $this->initMetabox(); + ); - } + // call this + $this->initMetabox(); + } - // html + save dealt with by parent class :) + // html + save dealt with by parent class :) } -/* ====================================================== - / Create Tags Box - ====================================================== */ - - - +/* +====================================================== + / Create Tags Box + ====================================================== */ +/* +====================================================== + Invoice Actions Metabox + ====================================================== */ +class zeroBS__Metabox_InvoiceActions extends zeroBS__Metabox { + public function __construct( $plugin_file ) { -/* ====================================================== - Invoice Actions Metabox - ====================================================== */ - - class zeroBS__Metabox_InvoiceActions extends zeroBS__Metabox{ - - public function __construct( $plugin_file ) { - - // set these - $this->objType = 'invoice'; - $this->metaboxID = 'zerobs-invoice-actions'; - $this->metaboxTitle = __('Invoice Actions','zero-bs-crm'); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-invoice-edit'; - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( + // set these + $this->objType = 'invoice'; + $this->metaboxID = 'zerobs-invoice-actions'; + $this->metaboxTitle = __( 'Invoice Actions', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-invoice-edit'; + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( - 'can_hide' => false, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved + 'can_hide' => false, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - ); + ); - // call this - $this->initMetabox(); + // call this + $this->initMetabox(); + } - } + public function html( $invoice, $metabox ) { + ?> +
- public function html( $invoice, $metabox ) { - ?>
+
-
+ 0){ // existing + if ( $invoiceID > 0 ) { // existing - ?> + ?> - + -
+
-
+
-
-
- -
- -
- +
+ + + +
+ +
+ +
+ + ?> - + -
+
+ array( - 'note' => array( 'label' => __( 'Note', 'zero-bs-crm' ), 'ico' => 'fa-sticky-note-o' ), - 'call' => array( 'label' => __( 'Call', 'zero-bs-crm' ), 'ico' => 'fa-phone-square' ), - 'email' => array( 'label' => __( 'Email', 'zero-bs-crm' ), 'ico' => 'fa-envelope-o' ), - 'mail' => array( 'label' => __( 'Mail', 'zero-bs-crm' ), 'ico' => 'fa-envelope-o' ), - 'meeting' => array( 'label' => __( 'Meeting', 'zero-bs-crm' ), 'ico' => 'fa-users' ), - 'quote__sent' => array( 'label' => __( 'Quote: Sent', 'zero-bs-crm' ), 'ico' => 'fa-share-square-o' ), - 'quote__accepted' => array( 'label' => __( 'Quote: Accepted', 'zero-bs-crm' ), 'ico' => 'fa-thumbs-o-up' ), - 'quote__refused' => array( 'label' => __( 'Quote: Refused', 'zero-bs-crm' ), 'ico' => 'fa-ban' ), - 'invoice__sent' => array( 'label' => __( 'Invoice: Sent', 'zero-bs-crm' ), 'ico' => 'fa-share-square-o' ), - 'invoice__part_paid' => array( 'label' => __( 'Invoice: Part Paid', 'zero-bs-crm' ), 'ico' => 'fa-money' ), - 'invoice__paid' => array( 'label' => __( 'Invoice: Paid', 'zero-bs-crm' ), 'ico' => 'fa-money' ), - 'invoice__refunded' => array( 'label' => __( 'Invoice: Refunded', 'zero-bs-crm' ), 'ico' => 'fa-money' ), - 'transaction' => array( 'label' => __( 'Transaction', 'zero-bs-crm' ), 'ico' => 'fa-credit-card' ), - 'feedback' => array( 'label' => __( 'Feedback', 'zero-bs-crm' ), 'ico' => 'fa-commenting' ), - 'tweet' => array( 'label' => __( 'Tweet', 'zero-bs-crm' ), 'ico' => 'fa-twitter' ), - 'facebook_post' => array( 'label' => __( 'Facebook Post', 'zero-bs-crm' ), 'ico' => 'fa-facebook-official' ), - 'other_contact' => array( 'label' => __( 'Other contact', 'zero-bs-crm' ), 'ico' => 'fa-users' ), - 'created' => array( 'locked' => true, 'label' => __( 'Created', 'zero-bs-crm' ), 'ico' => 'fa-plus-circle' ), - 'updated' => array( 'locked' => true, 'label' => __( 'Updated', 'zero-bs-crm' ), 'ico' => 'fa-pencil-square-o' ), - 'quote_created' => array( 'locked' => true, 'label' => __( 'Quote Created', 'zero-bs-crm' ), 'ico' => 'fa-plus-circle' ), - 'invoice_created' => array( 'locked' => true, 'label' => __( 'Invoice Created', 'zero-bs-crm' ), 'ico' => 'fa-plus-circle' ), - 'event_created' => array( 'locked' => true, 'label' => __( 'Task Created', 'zero-bs-crm' ), 'ico' => 'fa-calendar' ), - 'task_created' => array( 'locked' => true, 'label' => __( 'Task Created', 'zero-bs-crm' ), 'ico' => 'fa-calendar' ), - 'transaction_created' => array( 'locked' => true, 'label' => __( 'Transaction Created', 'zero-bs-crm' ), 'ico' => 'fa-credit-card' ), - 'transaction_updated' => array( 'locked' => true, 'label' => __( 'Transaction Updated', 'zero-bs-crm' ), 'ico' => 'fa-credit-card' ), - 'transaction_deleted' => array( 'locked' => true, 'label' => __( 'Transaction Deleted', 'zero-bs-crm' ), 'ico' => 'fa-credit-card' ), - 'form_filled' => array( 'locked' => true, 'label' => __( 'Form Filled', 'zero-bs-crm' ), 'ico' => 'fa-wpforms' ), - 'api_action' => array( 'locked' => true, 'label' => __( 'API Action', 'zero-bs-crm' ), 'ico' => 'fa-random' ), - 'bulk_action__merge' => array( 'locked' => true, 'label' => __( 'Bulk Action: Merge', 'zero-bs-crm' ), 'ico' => 'fa-compress' ), - 'client_portal_user_created' => array( 'locked' => true, 'label' => __( 'Client Portal User Created', 'zero-bs-crm' ), 'ico' => 'fa-id-card' ), - 'client_portal_access_changed' => array( 'locked' => true, 'label' => __( 'Client Portal Access Changed', 'zero-bs-crm' ), 'ico' => 'fa-id-card' ), - 'status_change' => array( 'locked' => true, 'label' => __( 'Status Change', 'zero-bs-crm' ), 'ico' => 'fa-random' ), - 'contact_changed_details_via_portal' => array( 'locked' => true, 'label' => __( 'Contact Changed via Portal', 'zero-bs-crm' ), 'ico' => 'fa-id-card' ), - 'contact_changed_details_via_wpprofile' => array( 'locked' => true, 'label' => __( 'Contact Changed via WordPress Profile', 'zero-bs-crm' ), 'ico' => 'fa-id-card' ), - 'contact_changed_details_via_woomyacc' => array( 'locked' => true, 'label' => __( 'Contact Changed via WooCommerce My Account', 'zero-bs-crm' ), 'ico' => 'fa-id-card' ), - 'contact_changed_details_via_mailpoet' => array( 'locked' => true, 'label' => __( 'Contact Changed via MailPoet', 'zero-bs-crm' ), 'ico' => 'fa-id-card' ), - 'subscriber_deleted_in_mailpoet' => array( 'locked' => true, 'label' => __( 'Subscriber deleted in MailPoet', 'zero-bs-crm' ), 'ico' => 'fa-times' ), - 'contact_change_details_attempt' => array( 'locked' => true, 'label' => __( 'Attempted Contact detail change', 'zero-bs-crm' ), 'ico' => 'fa-id-card' ), + 'note' => array( + 'label' => __( 'Note', 'zero-bs-crm' ), + 'ico' => 'fa-sticky-note-o', + ), + 'call' => array( + 'label' => __( 'Call', 'zero-bs-crm' ), + 'ico' => 'fa-phone-square', + ), + 'email' => array( + 'label' => __( 'Email', 'zero-bs-crm' ), + 'ico' => 'fa-envelope-o', + ), + 'mail' => array( + 'label' => __( 'Mail', 'zero-bs-crm' ), + 'ico' => 'fa-envelope-o', + ), + 'meeting' => array( + 'label' => __( 'Meeting', 'zero-bs-crm' ), + 'ico' => 'fa-users', + ), + 'quote__sent' => array( + 'label' => __( 'Quote: Sent', 'zero-bs-crm' ), + 'ico' => 'fa-share-square-o', + ), + 'quote__accepted' => array( + 'label' => __( 'Quote: Accepted', 'zero-bs-crm' ), + 'ico' => 'fa-thumbs-o-up', + ), + 'quote__refused' => array( + 'label' => __( 'Quote: Refused', 'zero-bs-crm' ), + 'ico' => 'fa-ban', + ), + 'invoice__sent' => array( + 'label' => __( 'Invoice: Sent', 'zero-bs-crm' ), + 'ico' => 'fa-share-square-o', + ), + 'invoice__part_paid' => array( + 'label' => __( 'Invoice: Part Paid', 'zero-bs-crm' ), + 'ico' => 'fa-money', + ), + 'invoice__paid' => array( + 'label' => __( 'Invoice: Paid', 'zero-bs-crm' ), + 'ico' => 'fa-money', + ), + 'invoice__refunded' => array( + 'label' => __( 'Invoice: Refunded', 'zero-bs-crm' ), + 'ico' => 'fa-money', + ), + 'transaction' => array( + 'label' => __( 'Transaction', 'zero-bs-crm' ), + 'ico' => 'fa-credit-card', + ), + 'feedback' => array( + 'label' => __( 'Feedback', 'zero-bs-crm' ), + 'ico' => 'fa-commenting', + ), + 'tweet' => array( + 'label' => __( 'Tweet', 'zero-bs-crm' ), + 'ico' => 'fa-twitter', + ), + 'facebook_post' => array( + 'label' => __( 'Facebook Post', 'zero-bs-crm' ), + 'ico' => 'fa-facebook-official', + ), + 'other_contact' => array( + 'label' => __( 'Other contact', 'zero-bs-crm' ), + 'ico' => 'fa-users', + ), + 'created' => array( + 'locked' => true, + 'label' => __( 'Created', 'zero-bs-crm' ), + 'ico' => 'fa-plus-circle', + ), + 'updated' => array( + 'locked' => true, + 'label' => __( 'Updated', 'zero-bs-crm' ), + 'ico' => 'fa-pencil-square-o', + ), + 'quote_created' => array( + 'locked' => true, + 'label' => __( 'Quote Created', 'zero-bs-crm' ), + 'ico' => 'fa-plus-circle', + ), + 'invoice_created' => array( + 'locked' => true, + 'label' => __( 'Invoice Created', 'zero-bs-crm' ), + 'ico' => 'fa-plus-circle', + ), + 'event_created' => array( + 'locked' => true, + 'label' => __( 'Task Created', 'zero-bs-crm' ), + 'ico' => 'fa-calendar', + ), + 'task_created' => array( + 'locked' => true, + 'label' => __( 'Task Created', 'zero-bs-crm' ), + 'ico' => 'fa-calendar', + ), + 'transaction_created' => array( + 'locked' => true, + 'label' => __( 'Transaction Created', 'zero-bs-crm' ), + 'ico' => 'fa-credit-card', + ), + 'transaction_updated' => array( + 'locked' => true, + 'label' => __( 'Transaction Updated', 'zero-bs-crm' ), + 'ico' => 'fa-credit-card', + ), + 'transaction_deleted' => array( + 'locked' => true, + 'label' => __( 'Transaction Deleted', 'zero-bs-crm' ), + 'ico' => 'fa-credit-card', + ), + 'form_filled' => array( + 'locked' => true, + 'label' => __( 'Form Filled', 'zero-bs-crm' ), + 'ico' => 'fa-wpforms', + ), + 'api_action' => array( + 'locked' => true, + 'label' => __( 'API Action', 'zero-bs-crm' ), + 'ico' => 'fa-random', + ), + 'bulk_action__merge' => array( + 'locked' => true, + 'label' => __( 'Bulk Action: Merge', 'zero-bs-crm' ), + 'ico' => 'fa-compress', + ), + 'client_portal_user_created' => array( + 'locked' => true, + 'label' => __( 'Client Portal User Created', 'zero-bs-crm' ), + 'ico' => 'fa-id-card', + ), + 'client_portal_access_changed' => array( + 'locked' => true, + 'label' => __( 'Client Portal Access Changed', 'zero-bs-crm' ), + 'ico' => 'fa-id-card', + ), + 'status_change' => array( + 'locked' => true, + 'label' => __( 'Status Change', 'zero-bs-crm' ), + 'ico' => 'fa-random', + ), + 'contact_changed_details_via_portal' => array( + 'locked' => true, + 'label' => __( 'Contact Changed via Portal', 'zero-bs-crm' ), + 'ico' => 'fa-id-card', + ), + 'contact_changed_details_via_wpprofile' => array( + 'locked' => true, + 'label' => __( 'Contact Changed via WordPress Profile', 'zero-bs-crm' ), + 'ico' => 'fa-id-card', + ), + 'contact_changed_details_via_woomyacc' => array( + 'locked' => true, + 'label' => __( 'Contact Changed via WooCommerce My Account', 'zero-bs-crm' ), + 'ico' => 'fa-id-card', + ), + 'contact_changed_details_via_mailpoet' => array( + 'locked' => true, + 'label' => __( 'Contact Changed via MailPoet', 'zero-bs-crm' ), + 'ico' => 'fa-id-card', + ), + 'subscriber_deleted_in_mailpoet' => array( + 'locked' => true, + 'label' => __( 'Subscriber deleted in MailPoet', 'zero-bs-crm' ), + 'ico' => 'fa-times', + ), + 'contact_change_details_attempt' => array( + 'locked' => true, + 'label' => __( 'Attempted Contact detail change', 'zero-bs-crm' ), + 'ico' => 'fa-id-card', + ), ), 'zerobs_company' => array( - 'note' => array( 'label' => __( 'Note', 'zero-bs-crm' ), 'ico' => 'fa-sticky-note-o' ), - 'call' => array( 'label' => __( 'Call', 'zero-bs-crm' ), 'ico' => 'fa-phone-square' ), - 'email' => array( 'label' => __( 'Email', 'zero-bs-crm' ), 'ico' => 'fa-envelope-o' ), - 'created' => array( 'locked' => true, 'label' => __( 'Created', 'zero-bs-crm' ), 'ico' => 'fa-plus-circle' ), - 'updated' => array( 'locked' => true, 'label' => __( 'Updated', 'zero-bs-crm' ), 'ico' => 'fa-pencil-square-o' ), + 'note' => array( + 'label' => __( 'Note', 'zero-bs-crm' ), + 'ico' => 'fa-sticky-note-o', + ), + 'call' => array( + 'label' => __( 'Call', 'zero-bs-crm' ), + 'ico' => 'fa-phone-square', + ), + 'email' => array( + 'label' => __( 'Email', 'zero-bs-crm' ), + 'ico' => 'fa-envelope-o', + ), + 'created' => array( + 'locked' => true, + 'label' => __( 'Created', 'zero-bs-crm' ), + 'ico' => 'fa-plus-circle', + ), + 'updated' => array( + 'locked' => true, + 'label' => __( 'Updated', 'zero-bs-crm' ), + 'ico' => 'fa-pencil-square-o', + ), ), - // // phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound ); - function zeroBSCRM_permifyLogType($logTypeStr=''){ +function zeroBSCRM_permifyLogType( $logTypeStr = '' ) { - return strtolower(str_replace(' ','_',str_replace(':','_',$logTypeStr))); - - } + return strtolower( str_replace( ' ', '_', str_replace( ':', '_', $logTypeStr ) ) ); +} - function zeroBSCRM_setupLogTypes(){ +function zeroBSCRM_setupLogTypes() { - global $zeroBSCRM_logTypes; + global $zeroBSCRM_logTypes; - // hide log types for objects that are disabled - $hide_quotes = zeroBSCRM_getSetting('feat_quotes') == -1; - $hide_invoices = zeroBSCRM_getSetting('feat_invs') == -1; - $hide_transactions = zeroBSCRM_getSetting('feat_transactions') == -1; + // hide log types for objects that are disabled + $hide_quotes = zeroBSCRM_getSetting( 'feat_quotes' ) == -1; + $hide_invoices = zeroBSCRM_getSetting( 'feat_invs' ) == -1; + $hide_transactions = zeroBSCRM_getSetting( 'feat_transactions' ) == -1; - foreach ( $zeroBSCRM_logTypes['zerobs_customer'] as $log_type => $log_type_value) { + foreach ( $zeroBSCRM_logTypes['zerobs_customer'] as $log_type => $log_type_value ) { if ( - $hide_quotes && str_starts_with( $log_type, 'quote' ) - || $hide_invoices && str_starts_with( $log_type, 'invoice' ) - || $hide_transactions && str_starts_with( $log_type, 'transaction' ) + $hide_quotes && str_starts_with( $log_type, 'quote' ) + || $hide_invoices && str_starts_with( $log_type, 'invoice' ) + || $hide_transactions && str_starts_with( $log_type, 'transaction' ) ) { - $zeroBSCRM_logTypes['zerobs_customer'][$log_type]['locked'] = true; - } - } - - // apply filters - $zeroBSCRM_logTypes = apply_filters('zbs_logtype_array', $zeroBSCRM_logTypes); - - } - -/* ====================================================== - / Declare Globals - ====================================================== */ - + $zeroBSCRM_logTypes['zerobs_customer'][ $log_type ]['locked'] = true; + } + } + // apply filters + $zeroBSCRM_logTypes = apply_filters( 'zbs_logtype_array', $zeroBSCRM_logTypes ); +} +/* +====================================================== + / Declare Globals + ====================================================== */ -/* ====================================================== - Logs (v3 DB3) Metabox - ====================================================== */ +/* +====================================================== + Logs (v3 DB3) Metabox + ====================================================== */ class zeroBS__Metabox_LogsV2 extends zeroBS__Metabox { - public $objtypeid = false; // child fills out e.g. ZBS_TYPE_CONTACT - public $metaboxLocation = 'normal'; + public $objtypeid = false; // child fills out e.g. ZBS_TYPE_CONTACT + public $metaboxLocation = 'normal'; /** * The legacy object name (e.g. 'zerobs_customer') @@ -148,1463 +293,1493 @@ class zeroBS__Metabox_LogsV2 extends zeroBS__Metabox { */ private $postType; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase - public function __construct( $plugin_file ) { + public function __construct( $plugin_file ) { - // call this - $this->initMetabox(); + // call this + $this->initMetabox(); + } - } + public function html( $obj, $metabox ) { - public function html( $obj, $metabox ) { + global $zbs; - global $zbs; - - // needs conversion to set this v3+ - // // obj type (1 => zerobs_customer) - // we load from DAL defaults, if objTypeID passed (overriding anything passed, if empty/false) + // needs conversion to set this v3+ + // // obj type (1 => zerobs_customer) + // we load from DAL defaults, if objTypeID passed (overriding anything passed, if empty/false) if ( isset( $this->objtypeid ) ) { - $objTypeID = (int)$this->objtypeid; - if ($objTypeID > 0){ - - // obj type (1 => zerobs_customer) - $objTypeStr = $zbs->DAL->typeCPT($objTypeID); - if ((!isset($this->postType) || $this->postType == false) && !empty($objTypeStr)) $this->postType = $objTypeStr; - - } - } + $objTypeID = (int) $this->objtypeid; + if ( $objTypeID > 0 ) { + // obj type (1 => zerobs_customer) + $objTypeStr = $zbs->DAL->typeCPT( $objTypeID ); + if ( ( ! isset( $this->postType ) || $this->postType == false ) && ! empty( $objTypeStr ) ) { + $this->postType = $objTypeStr; + } + } + } - $objid = -1; if (is_array($obj) && isset($obj['id'])) $objid = $obj['id']; + $objid = -1; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $objid = $obj['id']; + } - #} Only load if is legit. - //if (in_array($this->postType,array('zerobs_customer'))){ - if (in_array($this->objtypeid,array(ZBS_TYPE_CONTACT,ZBS_TYPE_COMPANY))){ + #} Only load if is legit. + // if (in_array($this->postType,array('zerobs_customer'))){ + if ( in_array( $this->objtypeid, array( ZBS_TYPE_CONTACT, ZBS_TYPE_COMPANY ) ) ) { - #} Proceed + #} Proceed - #} Retrieve - $zbsLogs = $zbs->DAL->logs->getLogsForObj(array( + #} Retrieve + $zbsLogs = $zbs->DAL->logs->getLogsForObj( + array( - 'objtype' => $this->objtypeid, - 'objid' => $objid, + 'objtype' => $this->objtypeid, + 'objid' => $objid, - 'searchPhrase' => '', + 'searchPhrase' => '', - 'incMeta' => false, + 'incMeta' => false, - 'sortByField' => 'zbsl_created', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 100, + 'sortByField' => 'zbsl_created', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 100, - 'ignoreowner' => true + 'ignoreowner' => true, - )); + ) + ); - if (!is_array($zbsLogs)) $zbsLogs = array(); + if ( ! is_array( $zbsLogs ) ) { + $zbsLogs = array(); + } - - ?> - + ?> + - - - +
+ + - + - - + - + -

+
- 0){ } + #if (count($zbsLogs) > 0){ } - ?> -
+ ?> +
-
+
- - + typeInt = $typeInt; - + // these then use objtypeint to generate: - $typeStr = $zbs->DAL->objTypeKey( $typeInt ); - $this->objType = $typeStr; - $this->metaboxID = 'zerobs-'.$typeStr.'-owner'; // zerobs-contact-owner - $this->metaboxScreen = 'zbs-add-edit-'.$typeStr.'-edit'; //'zbs-add-edit-contact-edit' + $typeStr = $zbs->DAL->objTypeKey( $typeInt ); + $this->objType = $typeStr; + $this->metaboxID = 'zerobs-' . $typeStr . '-owner'; // zerobs-contact-owner + $this->metaboxScreen = 'zbs-add-edit-' . $typeStr . '-edit'; // 'zbs-add-edit-contact-edit' - $this->metaboxArea = 'side'; + $this->metaboxArea = 'side'; $this->metaboxLocation = 'low'; - $this->metaboxTitle = __( 'Assigned To', 'zero-bs-crm' ); + $this->metaboxTitle = __( 'Assigned To', 'zero-bs-crm' ); - // call this + // call this $this->initMetabox(); - } public function html( $obj, $metabox ) { @@ -51,30 +54,34 @@ public function html( $obj, $metabox ) { // localise ID if ( is_array( $obj ) && isset( $obj['id'] ) ) { - $objID = (int)$obj['id']; + $objID = (int) $obj['id']; $zbsThisOwner = zeroBS_getOwnerObj( $obj['owner'] ); } else { - $objID = -1; + $objID = -1; $zbsThisOwner = array(); } // can even change owner? $canGiveOwnership = $zbs->settings->get( 'usercangiveownership' ); - $canChangeOwner = ( $canGiveOwnership == "1" || current_user_can( 'administrator' ) ); + $canChangeOwner = ( $canGiveOwnership == '1' || current_user_can( 'administrator' ) ); // init $zbsPossibleOwners = array(); - switch ($this->typeInt){ + switch ( $this->typeInt ) { case ZBS_TYPE_CONTACT: // If allowed to change assignment, load other possible users - if ($canChangeOwner) $zbsPossibleOwners = zeroBS_getPossibleCustomerOwners(); + if ( $canChangeOwner ) { + $zbsPossibleOwners = zeroBS_getPossibleCustomerOwners(); + } break; case ZBS_TYPE_COMPANY: // If allowed to change assignment, load other possible users - if ($canChangeOwner) $zbsPossibleOwners = zeroBS_getPossibleCompanyOwners(); + if ( $canChangeOwner ) { + $zbsPossibleOwners = zeroBS_getPossibleCompanyOwners(); + } break; default: @@ -84,10 +91,10 @@ public function html( $obj, $metabox ) { } // Can change owner, or has owner details, then show... (this whole box will be hidden if setting says no ownerships) - if ($canChangeOwner || isset($zbsThisOwner['ID'])){ + if ( $canChangeOwner || isset( $zbsThisOwner['ID'] ) ) { // Either: "assigned to DAVE" or "assigned to DAVE (in drop down list)" - if (!$canChangeOwner) { + if ( ! $canChangeOwner ) { // simple unchangable ?> @@ -102,12 +109,12 @@ public function html( $obj, $metabox ) { ?>
'; - - #} pass this if already templated: - if ($useQuoteBuilder == 1 && isset($quote['template'])) echo ''; - - #} Nonce used for loading quote template, left in for now, could be centralised to normal sec nonce - echo ''; - - // we pass the hash along the chain here too :) - echo ''; - ?> + // Debug echo 'Quote:
'.print_r($quote,1).'
'; + + ?> + + 0 ) { + $quoteContactID = $quote['contact'][0]['id']; // get_post_meta($post->ID, 'zbs_customer_quote_customer', true); + } + $templateUsed = -1; + if ( is_array( $quote ) && isset( $quote['template'] ) ) { + $templateUsed = $quote['template']; // get_post_meta($post->ID, 'zbs_quote_template_id', true); + } + + #} this is a temp weird one, just passing onto meta for now (long day): + // ? Not used DAL3? + // $zbsTemplated = get_post_meta($post->ID, 'templated', true); + // if (!empty($zbsTemplated)) $quote['templated'] = true; + // quick WH predictive hack, not sure if viable - to test DAL3 + $quote['templated'] = false; + if ( $templateUsed !== -1 && ! empty( $templateUsed ) ) { + $quote['templated'] = true; + } + + #} if customer id is empty, but prefill isn't, use prefill + if ( $quoteContactID == -1 && isset( $_GET['zbsprefillcust'] ) ) { + $quoteContactID = (int) $_GET['zbsprefillcust']; + } + + #} pass to other metaboxes (cache?) + global $zbsCurrentEditQuote; + $zbsCurrentEditQuote = $quote; + + #} Retrieve fields from global + global $zbsCustomerQuoteFields; + $fields = $zbsCustomerQuoteFields; + // Debug echo 'Fields:
'.print_r($fields,1).'
'; + + #} Using "Quote Builder" or not? + $useQuoteBuilder = zeroBSCRM_getSetting( 'usequotebuilder' ); + + // Inputs out: + + #} New quote? + if ( ! isset( $quote['id'] ) ) { + echo ''; + } + + #} pass this if already templated: + if ( $useQuoteBuilder == 1 && isset( $quote['template'] ) ) { + echo ''; + } + + #} Nonce used for loading quote template, left in for now, could be centralised to normal sec nonce + echo ''; + + // we pass the hash along the chain here too :) + echo ''; + ?>
- 0){ + // DAL3 only show after saved, easier + if ( ! empty( $quoteID ) && $quoteID > 0 ) { ?>
- ' . esc_html( $quoteID ) . ''; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + ' . esc_html( $quoteID ) . ''; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>
- 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?> @@ -204,1175 +223,1237 @@ public function html( $quote, $metabox ) { ?>
- DAL->contacts->getContactNameWithFallback( $quoteContactID ); - $prefillStr = $zbs->DAL->contacts->getContactNameWithFallback( $quoteContactID ); - - } + } - #} Output select box - echo zeroBSCRM_CustomerTypeList('zbscrmjs_quoteCustomerSelect',$prefillStr,true,'zbscrmjs_quote_unsetCustomer'); + #} Output select box + echo zeroBSCRM_CustomerTypeList( 'zbscrmjs_quoteCustomerSelect', $prefillStr, true, 'zbscrmjs_quote_unsetCustomer' ); - #} Output input which will pass the value via post - ?> + + +
+
+
- #} if enabled, and new quote, or one which hasn't had the 'templated' meta key added. - if ($useQuoteBuilder == 1 && !isset($quote['template'])){ + +

+

- ?> -
-
+ + +
+

+ + + + +

+ + +

();

+ - -

-

+
+
+ - - -
-

- - -

();

- + // content (from other metabox actually) + if ( isset( $_POST['zbs_quote_content'] ) ) { -
-
- acceptable_html ); // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- to follow up with. + #} update templated vars + if ( isset( $_POST['zbs_quote_template_id'] ) ) { + $quote['template'] = (int) sanitize_text_field( $_POST['zbs_quote_template_id'] ); + } + } - } ?> + #} First up, save quote id! #TRANSITIONTOMETANO + // DAL 3 will probs move away from this, for now leaving for refactoring round 2 + // for now store as meta (though perhaps needs a new field zbsid) + $quoteOffset = zeroBSCRM_getQuoteOffset(); + $quoteZBSID = (int) $quoteID + $quoteOffset; + if ( isset( $_POST['zbsquoteid'] ) && ! empty( $_POST['zbsquoteid'] ) ) { + $quoteZBSID = (int) $_POST['zbsquoteid']; + } + // update_post_meta($post_id,"zbsid",$quoteID); + $extraMeta['zbsid'] = $quoteZBSID; + #} and increment this + if ( ! empty( $quoteZBSID ) ) { + zeroBSCRM_setMaxQuoteID( $quoteZBSID ); + } -
- '', - 'currency' => '', - 'value' => '', - 'date' => '', - 'template' => '', - 'content' => '', - 'notes' => '', - 'send_attachments' => -1, (removed 4.0.9) - 'hash' => '', - 'lastviewed' => '', - 'viewed_count' => '', - 'accepted' => '', - //'created' => '', - //'lastupdated' => '', - ); - */ - $extraMeta = array(); // can pass any additional meta here - - // retrieve _POST into arr - //global $zbsCustomerQuoteFields; - //$zbsCustomerQuoteMeta = zeroBSCRM_save_fields($zbsCustomerQuoteFields,'zbscq_'); - $autoGenAutonumbers = true; // generate if not set :) - $removeEmpties = false; // req for autoGenAutonumbers - $quote = zeroBS_buildObjArr($_POST,array(),'zbscq_','',$removeEmpties,ZBS_TYPE_QUOTE,$autoGenAutonumbers); - - // Use the tag-class function to retrieve any tags so we can add inline. - // Save tags against objid - $quote['tags'] = zeroBSCRM_tags_retrieveFromPostBag(true,ZBS_TYPE_QUOTE); - - // we always get this, because it's used below, but not part of buildObjArr (currently at 3.0) - if ($quoteID > 0) $quote['template'] = (int)$zbs->DAL->quotes->getQuoteTemplateID($quoteID); - - // content (from other metabox actually) - if (isset($_POST['zbs_quote_content'])) { - - #} Save content - //$data=htmlspecialchars($_POST['zbs_quote_content'], ENT_COMPAT); - $quote['content'] = wp_kses( $_POST['zbs_quote_content'], $zbs->acceptable_html ); // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- to follow up with. - #} update templated vars - if (isset($_POST['zbs_quote_template_id'])) $quote['template'] = (int)sanitize_text_field($_POST['zbs_quote_template_id']); - - } - - #} First up, save quote id! #TRANSITIONTOMETANO - // DAL 3 will probs move away from this, for now leaving for refactoring round 2 - // for now store as meta (though perhaps needs a new field zbsid) - $quoteOffset = zeroBSCRM_getQuoteOffset(); - $quoteZBSID = (int)$quoteID+$quoteOffset; if (isset($_POST['zbsquoteid']) && !empty($_POST['zbsquoteid'])) $quoteZBSID = (int)$_POST['zbsquoteid']; - //update_post_meta($post_id,"zbsid",$quoteID); - $extraMeta['zbsid'] = $quoteZBSID; - #} and increment this - if (!empty($quoteZBSID)) zeroBSCRM_setMaxQuoteID($quoteZBSID); - - // assignments - $zbsQuoteContact = -1; if (isset($_POST['zbscq_customer'])) $zbsQuoteContact = (int)sanitize_text_field($_POST['zbscq_customer']); - $quote['contacts'] = ($zbsQuoteContact > 0) ? array($zbsQuoteContact) : array(); - $zbsQuoteCompany = -1; if (isset($_POST['zbscq_company'])) $zbsQuoteCompany = (int)sanitize_text_field($_POST['zbscq_company']); - $quote['companies'] = ($zbsQuoteCompany > 0) ? array($zbsQuoteCompany) : array(); - - /* line item (temp here from Inv metabox, not yet implemented in ui) - //new way.. now not limited to 30 lines as now they are stored in [] type array in JS draw - $zbsInvoiceLines = array(); - foreach($_POST['zbsli_itemname'] as $k => $v){ - - $ks = sanitize_text_field( $k ); // at least this - - $zbsInvoiceLines[$ks]['title'] = sanitize_text_field($_POST['zbsli_itemname'][$k]); - $zbsInvoiceLines[$ks]['desc'] = sanitize_text_field($_POST['zbsli_itemdes'][$k]); - $zbsInvoiceLines[$ks]['quantity'] = sanitize_text_field($_POST['zbsli_quan'][$k]); - $zbsInvoiceLines[$ks]['price'] = sanitize_text_field($_POST['zbsli_price'][$k]); - $zbsInvoiceLines[$ks]['tax'] = sanitize_text_field($_POST['zbsli_tax'][$k]); - - } - if (count($zbsInvoiceLines) > 0) $invoice['lineitems'] = $zbsInvoiceLines; - */ - - // Status Overwrites (manual changes, only after initial save) - if ($quoteID > 0 && isset($_POST['quote_status'])){ - - switch ($_POST['quote_status']){ + // assignments + $zbsQuoteContact = -1; + if ( isset( $_POST['zbscq_customer'] ) ) { + $zbsQuoteContact = (int) sanitize_text_field( $_POST['zbscq_customer'] ); + } + $quote['contacts'] = ( $zbsQuoteContact > 0 ) ? array( $zbsQuoteContact ) : array(); + $zbsQuoteCompany = -1; + if ( isset( $_POST['zbscq_company'] ) ) { + $zbsQuoteCompany = (int) sanitize_text_field( $_POST['zbscq_company'] ); + } + $quote['companies'] = ( $zbsQuoteCompany > 0 ) ? array( $zbsQuoteCompany ) : array(); - case 'draft': - // if changing to draft, remove any accepted date + template ID - $quote['accepted'] = 0; - $quote['template'] = -1; + /* + line item (temp here from Inv metabox, not yet implemented in ui) + //new way.. now not limited to 30 lines as now they are stored in [] type array in JS draw + $zbsInvoiceLines = array(); + foreach($_POST['zbsli_itemname'] as $k => $v){ - break; - case 'published': + $ks = sanitize_text_field( $k ); // at least this - // if changing to published, just needs accepted unsetting, and if no template, populate - $quote['accepted'] = 0; - - // got template? - - // if not already set, set, otherwise leave existing set time in. - if (!isset($quote['template']) || $quote['template'] <= 0) { - - // hacky setting of it to unlikely cieling - $quote['template'] = 99999; - - } - - break; - case 'accepted': + $zbsInvoiceLines[$ks]['title'] = sanitize_text_field($_POST['zbsli_itemname'][$k]); + $zbsInvoiceLines[$ks]['desc'] = sanitize_text_field($_POST['zbsli_itemdes'][$k]); + $zbsInvoiceLines[$ks]['quantity'] = sanitize_text_field($_POST['zbsli_quan'][$k]); + $zbsInvoiceLines[$ks]['price'] = sanitize_text_field($_POST['zbsli_price'][$k]); + $zbsInvoiceLines[$ks]['tax'] = sanitize_text_field($_POST['zbsli_tax'][$k]); - // if not already accepted, mark accepted. + } + if (count($zbsInvoiceLines) > 0) $invoice['lineitems'] = $zbsInvoiceLines; + */ - // existing - $accepted = (int)$zbs->DAL->quotes->getQuoteAcceptedTime($quoteID); + // Status Overwrites (manual changes, only after initial save) + if ( $quoteID > 0 && isset( $_POST['quote_status'] ) ) { - // if not already set, set, otherwise leave existing set time in. - if ($accepted <= 0) { + switch ( $_POST['quote_status'] ) { - // set it (first time, manual) - $quote['accepted'] = time(); - $quote['acceptedsigned'] = 'manual'; - $quote['acceptedip'] = ''; + case 'draft': + // if changing to draft, remove any accepted date + template ID + $quote['accepted'] = 0; + $quote['template'] = -1; - } + break; + case 'published': + // if changing to published, just needs accepted unsetting, and if no template, populate + $quote['accepted'] = 0; - break; + // got template? - } - } + // if not already set, set, otherwise leave existing set time in. + if ( ! isset( $quote['template'] ) || $quote['template'] <= 0 ) { + // hacky setting of it to unlikely cieling + $quote['template'] = 99999; - // add/update - $addUpdateReturn = $zbs->DAL->quotes->addUpdateQuote(array( + } - 'id' => $quoteID, - 'data' => $quote, - 'extraMeta' => $extraMeta, - 'limitedFields' => -1 + break; + case 'accepted': + // if not already accepted, mark accepted. - )); + // existing + $accepted = (int) $zbs->DAL->quotes->getQuoteAcceptedTime( $quoteID ); - // Note: For NEW objs, we make sure a global is set here, that other update funcs can catch - // ... so it's essential this one runs first! - // this is managed in the metabox Class :) - if ($quoteID == -1 && !empty($addUpdateReturn) && $addUpdateReturn != -1) { - - $quoteID = $addUpdateReturn; - global $zbsJustInsertedMetaboxID; $zbsJustInsertedMetaboxID = $quoteID; + // if not already set, set, otherwise leave existing set time in. + if ( $accepted <= 0 ) { - // set this so it redirs - $this->newRecordNeedsRedir = true; - } + // set it (first time, manual) + $quote['accepted'] = time(); + $quote['acceptedsigned'] = 'manual'; + $quote['acceptedip'] = ''; - // success? - if ($addUpdateReturn != -1 && $addUpdateReturn > 0){ + } - // Update Msg - // this adds an update message which'll go out ahead of any content - // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); - // This adds to edit page - $this->updateMessage(); + break; - // catch any non-critical messages - $nonCriticalMessages = $zbs->DAL->getErrors(ZBS_TYPE_QUOTE); - if (is_array($nonCriticalMessages) && count($nonCriticalMessages) > 0) $this->dalNoticeMessage($nonCriticalMessages); + } + } + // add/update + $addUpdateReturn = $zbs->DAL->quotes->addUpdateQuote( + array( - } else { + 'id' => $quoteID, + 'data' => $quote, + 'extraMeta' => $extraMeta, + 'limitedFields' => -1, - // fail somehow - $failMessages = $zbs->DAL->getErrors(ZBS_TYPE_QUOTE); + ) + ); - // show msg (retrieved from DAL err stack) - if (is_array($failMessages) && count($failMessages) > 0) - $this->dalErrorMessage($failMessages); - else - $this->dalErrorMessage(array(__('Insert/Update Failed with general error','zero-bs-crm'))); + // Note: For NEW objs, we make sure a global is set here, that other update funcs can catch + // ... so it's essential this one runs first! + // this is managed in the metabox Class :) + if ( $quoteID == -1 && ! empty( $addUpdateReturn ) && $addUpdateReturn != -1 ) { - // pass the pre-fill: - global $zbsObjDataPrefill; $zbsObjDataPrefill = $quote; + $quoteID = $addUpdateReturn; + global $zbsJustInsertedMetaboxID; + $zbsJustInsertedMetaboxID = $quoteID; - - } + // set this so it redirs + $this->newRecordNeedsRedir = true; + } - } + // success? + if ( $addUpdateReturn != -1 && $addUpdateReturn > 0 ) { - return $quote; - } + // Update Msg + // this adds an update message which'll go out ahead of any content + // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); + // This adds to edit page + $this->updateMessage(); - // This catches 'new' contacts + redirs to right url - public function post_save_data($objID,$obj){ + // catch any non-critical messages + $nonCriticalMessages = $zbs->DAL->getErrors( ZBS_TYPE_QUOTE ); + if ( is_array( $nonCriticalMessages ) && count( $nonCriticalMessages ) > 0 ) { + $this->dalNoticeMessage( $nonCriticalMessages ); + } + } else { - if ($this->newRecordNeedsRedir){ + // fail somehow + $failMessages = $zbs->DAL->getErrors( ZBS_TYPE_QUOTE ); - global $zbsJustInsertedMetaboxID; - if (!empty($zbsJustInsertedMetaboxID) && $zbsJustInsertedMetaboxID > 0){ + // show msg (retrieved from DAL err stack) + if ( is_array( $failMessages ) && count( $failMessages ) > 0 ) { + $this->dalErrorMessage( $failMessages ); + } else { + $this->dalErrorMessage( array( __( 'Insert/Update Failed with general error', 'zero-bs-crm' ) ) ); + } - // redir - wp_redirect( jpcrm_esc_link('edit',$zbsJustInsertedMetaboxID,$this->objType) ); - exit( 0 ); + // pass the pre-fill: + global $zbsObjDataPrefill; + $zbsObjDataPrefill = $quote; - } + } + } - } + return $quote; + } - } + // This catches 'new' contacts + redirs to right url + public function post_save_data( $objID, $obj ) { - public function updateMessage(){ + if ( $this->newRecordNeedsRedir ) { - global $zbs; + global $zbsJustInsertedMetaboxID; + if ( ! empty( $zbsJustInsertedMetaboxID ) && $zbsJustInsertedMetaboxID > 0 ) { - // zbs-not-urgent means it'll auto hide after 1.5s - // genericified from DAL3.0 - $msg = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',$zbs->DAL->typeStr($zbs->DAL->objTypeKey($this->objType)).' '.__('Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); + // redir + wp_redirect( jpcrm_esc_link( 'edit', $zbsJustInsertedMetaboxID, $this->objType ) ); + exit( 0 ); - $zbs->pageMessages[] = $msg; + } + } + } - } - } + public function updateMessage() { + global $zbs; -/* ====================================================== - / Quote Metabox - ====================================================== */ + // zbs-not-urgent means it'll auto hide after 1.5s + // genericified from DAL3.0 + $msg = zeroBSCRM_UI2_messageHTML( 'info olive mini zbs-not-urgent', $zbs->DAL->typeStr( $zbs->DAL->objTypeKey( $this->objType ) ) . ' ' . __( 'Updated', 'zero-bs-crm' ), '', 'address book outline', 'contactUpdated' ); + $zbs->pageMessages[] = $msg; + } +} -/* ====================================================== - Quote Content Metabox - ====================================================== */ +/* +====================================================== + / Quote Metabox + ====================================================== */ - class zeroBS__Metabox_QuoteContent extends zeroBS__Metabox{ +/* +====================================================== + Quote Content Metabox + ====================================================== */ - public function __construct( $plugin_file ) { +class zeroBS__Metabox_QuoteContent extends zeroBS__Metabox { - // set these - $this->objType = 'quote'; - $this->metaboxID = 'zerobs-quote-content-edit'; - $this->metaboxTitle = __('Step 2: Quote Content','zero-bs-crm'); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-quote-edit'; - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->saveOrder = 1; - $this->capabilities = array( + public function __construct( $plugin_file ) { - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved + // set these + $this->objType = 'quote'; + $this->metaboxID = 'zerobs-quote-content-edit'; + $this->metaboxTitle = __( 'Step 2: Quote Content', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-quote-edit'; + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'low'; + $this->saveOrder = 1; + $this->capabilities = array( - ); + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - // call this - $this->initMetabox(); + ); - } + // call this + $this->initMetabox(); + } - public function html( $quote, $metabox ) { + public function html( $quote, $metabox ) { - global $zbs; + global $zbs; - // localise ID & content - $quoteID = -1; if (is_array($quote) && isset($quote['id'])) $quoteID = (int)$quote['id']; - $quote_content = ''; + // localise ID & content + $quoteID = -1; + if ( is_array( $quote ) && isset( $quote['id'] ) ) { + $quoteID = (int) $quote['id']; + } + $quote_content = ''; if ( is_array( $quote ) && isset( $quote['content'] ) ) { $quote_content = wp_kses( $quote['content'], $zbs->acceptable_html ); } - - // remove "Add contact form" button from Jetpack - remove_action( 'media_buttons', 'grunion_media_button', 999 ); - wp_editor( - $quote_content, - 'zbs_quote_content', - array( - 'editor_height' => 580, - 'wpautop' => false, - ) - ); - } - - // saved via main metabox - } - - -/* ====================================================== - / Quote Content Metabox - ====================================================== */ - + // remove "Add contact form" button from Jetpack + remove_action( 'media_buttons', 'grunion_media_button', 999 ); + wp_editor( + $quote_content, + 'zbs_quote_content', + array( + 'editor_height' => 580, + 'wpautop' => false, + ) + ); + } + + // saved via main metabox +} -/* ====================================================== - Quote Next Step Metabox - ====================================================== */ +/* +====================================================== + / Quote Content Metabox + ====================================================== */ - class zeroBS__Metabox_QuoteNextStep extends zeroBS__Metabox{ +/* +====================================================== + Quote Next Step Metabox + ====================================================== */ - public function __construct( $plugin_file ) { +class zeroBS__Metabox_QuoteNextStep extends zeroBS__Metabox { - // set these - $this->objType = 'quote'; - $this->metaboxID = 'zerobs-quote-nextstep'; - $this->metaboxTitle = __('Step 3: Publish and Send','zero-bs-crm'); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-quote-edit'; - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->saveOrder = 1; - $this->capabilities = array( + public function __construct( $plugin_file ) { - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved + // set these + $this->objType = 'quote'; + $this->metaboxID = 'zerobs-quote-nextstep'; + $this->metaboxTitle = __( 'Step 3: Publish and Send', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-quote-edit'; + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'low'; + $this->saveOrder = 1; + $this->capabilities = array( - ); + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - // call this - $this->initMetabox(); + ); - } + // call this + $this->initMetabox(); + } - public function html( $quote, $metabox ) { + public function html( $quote, $metabox ) { if ( $quote === false ) { $quote = array(); } - global $zbs; + global $zbs; + + // localise ID & content + $quoteID = -1; + if ( is_array( $quote ) && isset( $quote['id'] ) ) { + $quoteID = (int) $quote['id']; + } - // localise ID & content - $quoteID = -1; if (is_array($quote) && isset($quote['id'])) $quoteID = (int)$quote['id']; + #} retrieve + // some legacy bits from CPT days: + $quoteContactID = -1; + if ( is_array( $quote ) && isset( $quote['contact'] ) && is_array( $quote['contact'] ) && count( $quote['contact'] ) > 0 ) { + $quoteContactID = $quote['contact'][0]['id']; // get_post_meta($post->ID, 'zbs_customer_quote_customer', true); + } + $templateUsed = -1; + if ( is_array( $quote ) && isset( $quote['template'] ) ) { + $templateUsed = $quote['template']; // get_post_meta($post->ID, 'zbs_quote_template_id', true); + } - #} retrieve - // some legacy bits from CPT days: - $quoteContactID = -1; if (is_array($quote) && isset($quote['contact']) && is_array($quote['contact']) && count($quote['contact']) > 0) $quoteContactID = $quote['contact'][0]['id']; //get_post_meta($post->ID, 'zbs_customer_quote_customer', true); - $templateUsed = -1; if (is_array($quote) && isset($quote['template'])) $templateUsed = $quote['template']; //get_post_meta($post->ID, 'zbs_quote_template_id', true); - - #} Using "Quote Builder" or not? - $useQuoteBuilder = zeroBSCRM_getSetting('usequotebuilder'); - $useHash = zeroBSCRM_getSetting('easyaccesslinks'); + #} Using "Quote Builder" or not? + $useQuoteBuilder = zeroBSCRM_getSetting( 'usequotebuilder' ); + $useHash = zeroBSCRM_getSetting( 'easyaccesslinks' ); - #} if enabled, and new quote, or one which hasn't had the 'templated' meta key added. - if ($useQuoteBuilder == "1") { + #} if enabled, and new quote, or one which hasn't had the 'templated' meta key added. + if ( $useQuoteBuilder == '1' ) { - // retrieve email $contactEmail = ''; - $contactEmail = $zbs->DAL->contacts->getContactEmail($quoteContactID);//zeroBS_contactEmail($quoteContactID); + // retrieve email $contactEmail = ''; + $contactEmail = $zbs->DAL->contacts->getContactEmail( $quoteContactID );// zeroBS_contactEmail($quoteContactID); - // quick WH predictive hack, not sure if viable - to test DAL3 - $quote['templated'] = false; if ($templateUsed !== -1 && !empty($templateUsed)) $quote['templated'] = true; + // quick WH predictive hack, not sure if viable - to test DAL3 + $quote['templated'] = false; + if ( $templateUsed !== -1 && ! empty( $templateUsed ) ) { + $quote['templated'] = true; + } - #} first load? - if (gettype($quote) != "array" || !isset($quote['templated'])){ + #} first load? + if ( gettype( $quote ) != 'array' || ! isset( $quote['templated'] ) ) { - ?> -
+ ?> +
- -

+ +

:

- + -
+
- -
- -

- -
- +
+ +

+ +
+ + ?> -
- var zbscrmjs_secToken = \'' . esc_js( wp_create_nonce( 'zbscrmjs-ajax-nonce' ) ) . '\';'; - ?> +
+ var zbscrmjs_secToken = \'' . esc_js( wp_create_nonce( 'zbscrmjs-ajax-nonce' ) ) . '\';'; + ?> - -

+ +

:

- + -
+

:

- -

+ +

- -
- modules, 'portal' ) ) : - $quote_id_or_hash = $useHash ? $quote['hash'] : $quoteID; - $single_quote_slug = $zbs->modules->portal->get_endpoint( ZBS_TYPE_QUOTE ); - $preview_url = zeroBS_portal_link( $single_quote_slug, $quote_id_or_hash ); - -?> -
-

:

-

-
- + +
+ modules, 'portal' ) ) : + $quote_id_or_hash = $useHash ? $quote['hash'] : $quoteID; + $single_quote_slug = $zbs->modules->portal->get_endpoint( ZBS_TYPE_QUOTE ); + $preview_url = zeroBS_portal_link( $single_quote_slug, $quote_id_or_hash ); - -
-

-

+ ?> +
+

:

+

+
+ + + +
+

+

- -
- - - -
- - 0){ - - // Contact, but they don't have an email addr on file: ?> - -
- -

-
-

:

-

-

-
- -
- - - -
- -

-
-

:

-

-
- -
- - + + + +
- } + 0 ) { + // Contact, but they don't have an email addr on file: + ?> -/* ====================================================== - / Quote Actions Metabox - ====================================================== */ +
+

+
+

:

+

+

+
+
+ +
+

+
+

:

+

+
-/* ====================================================== - Quote files Metabox - ====================================================== */ +
- class zeroBS__Metabox_QuoteFiles extends zeroBS__Metabox{ + postType = 'zerobs_customer'; - $this->objType = 'quote'; - $this->metaboxID = 'zerobs-quote-files'; - $this->metaboxTitle = __('Associated Files',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-quote-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'low'; - $this->capabilities = array( + // nothing to save. +} - 'can_hide' => true, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => true, // can be added as tab - 'can_minimise' => true // can be minimised +/* +====================================================== + / Quote Actions Metabox + ====================================================== */ - ); +/* +====================================================== + Quote files Metabox + ====================================================== */ - // call this - $this->initMetabox(); +class zeroBS__Metabox_QuoteFiles extends zeroBS__Metabox { - } + public function __construct( $plugin_file ) { - public function html( $quote, $metabox ) { + // DAL3 switched for objType $this->postType = 'zerobs_customer'; + $this->objType = 'quote'; + $this->metaboxID = 'zerobs-quote-files'; + $this->metaboxTitle = __( 'Associated Files', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-quote-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'low'; + $this->capabilities = array( - global $zbs; + 'can_hide' => true, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => true, // can be added as tab + 'can_minimise' => true, // can be minimised - $html = ''; + ); - // localise ID - $quoteID = -1; if (is_array($quote) && isset($quote['id'])) $quoteID = (int)$quote['id']; + // call this + $this->initMetabox(); + } - #} retrieve - $zbsFiles = array(); if ($quoteID > 0) $zbsFiles = zeroBSCRM_files_getFiles('quote',$quoteID); + public function html( $quote, $metabox ) { - ?> + global $zbs; - 0){ - ?> - - DAL->transactions->transaction_exists( $transaction['parent'] ) - ) { + if ( + // has Refund Type + isset( $transaction['type'] ) && $transaction['type'] == __( 'Refund', 'zero-bs-crm' ) + && + // has parent ID based transaction + isset( $transaction['parent'] ) && $zbs->DAL->transactions->transaction_exists( $transaction['parent'] ) + ) { - // get parent ref - $parent_ref = $zbs->DAL->transactions->get_transaction_ref( $transaction['parent'] ); + // get parent ref + $parent_ref = $zbs->DAL->transactions->get_transaction_ref( $transaction['parent'] ); - ?> + ?>

- +

@@ -272,17 +284,17 @@ public function html( $transaction, $metabox ) { } // shipping? - $useShipping = zeroBSCRM_getSetting('shippingfortransactions'); - if ($useShipping != 1){ + $useShipping = zeroBSCRM_getSetting( 'shippingfortransactions' ); + if ( $useShipping != 1 ) { $skipList[] = 'shipping'; $skipList[] = 'shipping_taxes'; - } + } // output additional fields - zeroBSCRM_html_editFields( $transaction, $zbsTransactionFields,'zbst_', $skipList ); + zeroBSCRM_html_editFields( $transaction, $zbsTransactionFields, 'zbst_', $skipList ); // use paid/completed dates? - $usePaidDates = zeroBSCRM_getSetting('paiddatestransaction'); + $usePaidDates = zeroBSCRM_getSetting( 'paiddatestransaction' ); if ( $usePaidDates === 1 ) { ?>
@@ -328,61 +340,63 @@ public function html( $transaction, $metabox ) {
+ ?> -
- 0 ) { + $zbsFiles = zeroBSCRM_files_getFiles( 'quote', $quoteID ); + } - echo ''; - $fileLineIndx++; + ?> + - } ?> - + // WH only slightly updated this for DAL3 - could do with a cleanup run (contact file edit has more functionality) - '; - - ?> - - -

()
:
- + objType = 'quote'; - $this->metaboxID = 'zerobs-quote-status-edit'; - $this->metaboxTitle = __('Quote Public Status','zero-bs-crm'); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-quote-edit'; - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'low'; - $this->saveOrder = 1; - $this->capabilities = array( + // Fire any 'post-upload-processing' (e.g. CPP makes thumbnails of pdf, jpg, etc.) + // not req invoicing: do_action('zbs_post_upload_contact',$upload); + } + } else { + wp_die( "The file type that you've uploaded is not an accepted file format." ); + } + } - 'can_hide' => false, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved + return $quote; + } +} - ); +/* +====================================================== + / Attach files to quote metabox + ====================================================== */ - global $useQuoteBuilder; +/* +====================================================== + Quote Accepted Details Metabox + ====================================================== */ +class zeroBS__Metabox_QuoteAcceptedDetails extends zeroBS__Metabox { - // call this - if ($useQuoteBuilder == "1") - $this->initMetabox(); + // this is for catching 'new' contacts + private $newRecordNeedsRedir = false; - } + public function __construct( $plugin_file ) { - public function html( $quote, $metabox ) { + // set these + $this->objType = 'quote'; + $this->metaboxID = 'zerobs-quote-status-edit'; + $this->metaboxTitle = __( 'Quote Public Status', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-quote-edit'; + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'low'; + $this->saveOrder = 1; + $this->capabilities = array( - // localise ID & template - $quoteID = -1; if (is_array($quote) && isset($quote['id'])) $quoteID = (int)$quote['id']; - $templateUsed = -1; if (is_array($quote) && isset($quote['template'])) $templateUsed = $quote['template']; + 'can_hide' => false, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - // quick WH predictive hack, not sure if viable - to test DAL3 - $quote['templated'] = false; if ($templateUsed !== -1 && !empty($templateUsed)) $quote['templated'] = true; - - global $useQuoteBuilder; + ); - #} if enabled, and new quote, or one which hasn't had the 'templated' meta key added. - #} ... also hide unless it's been "published" - if ($useQuoteBuilder == "1" && (is_array($quote) && isset($quote['templated']) && $quote['templated'])) { + global $useQuoteBuilder; - if (isset($quote) && is_array($quote) && isset($quote['accepted']) && $quote['accepted'] > 0){ + // call this + if ( $useQuoteBuilder == '1' ) { + $this->initMetabox(); + } + } - #} Deets - $acceptedDate = date(zeroBSCRM_getTimeFormat().' '.zeroBSCRM_getDateFormat(),$quote['accepted']); - $acceptedBy = $quote['acceptedsigned']; - $acceptedIP = $quote['acceptedip']; - - ?> + public function html( $quote, $metabox ) { - - - -
>
+ // localise ID & template + $quoteID = -1; + if ( is_array( $quote ) && isset( $quote['id'] ) ) { + $quoteID = (int) $quote['id']; + } + $templateUsed = -1; + if ( is_array( $quote ) && isset( $quote['template'] ) ) { + $templateUsed = $quote['template']; + } - + if ( isset( $quote ) && is_array( $quote ) && isset( $quote['accepted'] ) && $quote['accepted'] > 0 ) { - - - -
+ #} Deets + $acceptedDate = date( zeroBSCRM_getTimeFormat() . ' ' . zeroBSCRM_getDateFormat(), $quote['accepted'] ); + $acceptedBy = $quote['acceptedsigned']; + $acceptedIP = $quote['acceptedip']; - - } + + + + +
+>
- } else { // / only load if post type + - - } + + + +
- // nothing to save - } + + + objTypeID = ZBS_TYPE_QUOTE; - // DAL3 switched for objType $this->postType = 'zerobs_customer'; - $this->objType = 'quote'; - $this->metaboxID = 'zerobs-quote-tags'; - $this->metaboxTitle = __('Quote Tags',"zero-bs-crm"); - $this->metaboxScreen = 'zbs-add-edit-quote-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->showSuggestions = true; - $this->capabilities = array( + public function __construct( $plugin_file ) { - 'can_hide' => true, // can be hidden - 'areas' => array('side'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => false, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true // can be minimised + $this->objTypeID = ZBS_TYPE_QUOTE; + // DAL3 switched for objType $this->postType = 'zerobs_customer'; + $this->objType = 'quote'; + $this->metaboxID = 'zerobs-quote-tags'; + $this->metaboxTitle = __( 'Quote Tags', 'zero-bs-crm' ); + $this->metaboxScreen = 'zbs-add-edit-quote-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->showSuggestions = true; + $this->capabilities = array( - ); + 'can_hide' => true, // can be hidden + 'areas' => array( 'side' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => false, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised - // call this - $this->initMetabox(); + ); - } + // call this + $this->initMetabox(); + } - // html + save dealt with by parent class :) + // html + save dealt with by parent class :) } -/* ====================================================== - / Create Tags Box - ====================================================== */ - +/* +====================================================== + / Create Tags Box + ====================================================== */ -/* ====================================================== - Quote Actions Metabox - ====================================================== */ +/* +====================================================== + Quote Actions Metabox + ====================================================== */ - class zeroBS__Metabox_QuoteActions extends zeroBS__Metabox{ +class zeroBS__Metabox_QuoteActions extends zeroBS__Metabox { - public function __construct( $plugin_file ) { + public function __construct( $plugin_file ) { - // set these - $this->objType = 'quote'; - $this->metaboxID = 'zerobs-quote-actions'; - $this->metaboxTitle = __('Quote Actions','zero-bs-crm'); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-quote-edit'; - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( + // set these + $this->objType = 'quote'; + $this->metaboxID = 'zerobs-quote-actions'; + $this->metaboxTitle = __( 'Quote Actions', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-quote-edit'; + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( - 'can_hide' => false, // can be hidden - 'areas' => array('high'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved + 'can_hide' => false, // can be hidden + 'areas' => array( 'high' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - ); + ); - // call this - $this->initMetabox(); + // call this + $this->initMetabox(); + } - } + public function html( $quote, $metabox ) { - public function html( $quote, $metabox ) { + ?> +
- ?>
+
-
+ post_status) && $post->post_status != "auto-draft"){ + #} if a saved post... + // if (isset($post->post_status) && $post->post_status != "auto-draft"){ if ( $quoteID > 0 ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?> -
+
-
- -
- - -
+ // delete? -
- +
+ +
+ + +
+
+ -
+
+ 0){ - - // Tag List - $zeroBS__Metabox_TagList = new zeroBS__Metabox_TagList( __FILE__, $typeInt ); - - // Add Tags - $zeroBS__Metabox_TagAdd = new zeroBS__Metabox_TagAdd( __FILE__, $typeInt ); - - } - - } - - add_action( 'admin_init','zeroBSCRM_TagManagerMetaboxSetup'); - - -/* ====================================================== - / Init Func - ====================================================== */ - - - -/* ====================================================== - Declare Globals - ====================================================== */ - - #} Used throughout - // Don't know who added this, but GLOBALS are out of scope here - //global $zbsCustomerFields,$zbsCustomerQuoteFields,$zbsCustomerInvoiceFields; - -/* ====================================================== - / Declare Globals - ====================================================== */ - - - // PerfTest: zeroBSCRM_performanceTest_startTimer('custmetabox'); - -/* ====================================================== - Tag List Metabox - ====================================================== */ - - class zeroBS__Metabox_TagList extends zeroBS__Metabox{ +/* +====================================================== + Init Func + ====================================================== */ + +function zeroBSCRM_TagManagerMetaboxSetup() { + + // lazy page switch + $typeInt = -1; + if ( zeroBSCRM_is_customertags_page() ) { + $typeInt = ZBS_TYPE_CONTACT; + } + if ( zeroBSCRM_is_companytags_page() ) { + $typeInt = ZBS_TYPE_COMPANY; + } + if ( zeroBSCRM_is_quotetags_page() ) { + $typeInt = ZBS_TYPE_QUOTE; + } + if ( zeroBSCRM_is_invoicetags_page() ) { + $typeInt = ZBS_TYPE_INVOICE; + } + if ( zeroBSCRM_is_transactiontags_page() ) { + $typeInt = ZBS_TYPE_TRANSACTION; + } + if ( zeroBSCRM_is_formtags_page() ) { + $typeInt = ZBS_TYPE_FORM; + } + if ( zeroBSCRM_is_tasktags_page() ) { + $typeInt = ZBS_TYPE_TASK; + } + + if ( $typeInt > 0 ) { + + // Tag List + $zeroBS__Metabox_TagList = new zeroBS__Metabox_TagList( __FILE__, $typeInt ); + + // Add Tags + $zeroBS__Metabox_TagAdd = new zeroBS__Metabox_TagAdd( __FILE__, $typeInt ); + + } +} + + add_action( 'admin_init', 'zeroBSCRM_TagManagerMetaboxSetup' ); + +/* +====================================================== + / Init Func + ====================================================== */ + +/* +====================================================== + Declare Globals + ====================================================== */ + + #} Used throughout + // Don't know who added this, but GLOBALS are out of scope here + // global $zbsCustomerFields,$zbsCustomerQuoteFields,$zbsCustomerInvoiceFields; + +/* +====================================================== + / Declare Globals + ====================================================== */ + + // PerfTest: zeroBSCRM_performanceTest_startTimer('custmetabox'); + +/* +====================================================== + Tag List Metabox + ====================================================== */ + +class zeroBS__Metabox_TagList extends zeroBS__Metabox { /** * The legacy object name (e.g. 'zerobs_customer') @@ -77,126 +90,156 @@ class zeroBS__Metabox_TagList extends zeroBS__Metabox{ */ private $postType; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase - public function __construct( $plugin_file, $typeInt = ZBS_TYPE_CONTACT ) { - - global $zbs; - - // set these - $this->typeInt = $typeInt; - $this->postType = $zbs->DAL->typeCPT($typeInt); - $this->metaboxID = 'zerobs-'.$zbs->DAL->objTypeKey($typeInt).'-tags-edit'; - $this->metaboxTitle = __($zbs->DAL->typeStr($typeInt).' Tags',"zero-bs-crm"); - $this->metaboxScreen = 'zerobs_edit_tags'; // we can use anything here as is now using our func - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - // headless! - $this->headless = true; - - // call this - $this->initMetabox(); - - } - - public function html( $contact, $metabox ) { - - global $zbs; - - // Get all tags - $tags = $zbs->DAL->getTagsForObjType(array( - - 'objtypeid'=>$this->typeInt, - 'excludeEmpty'=>false, - 'withCount'=>true, - 'ignoreowner' => true, - // sort - 'sortByField' => 'tagcount', - 'sortOrder' => 'DESC' - - )); - - // pre-inject some potential js errors :) - ?>
- - - - - */ ?> - - - - - - 0){ - foreach ($tags as $tag){ - - $link = jpcrm_esc_link('listtagged',-1,$this->postType,-1,$tag['id']); - ?> - - - - */ ?> - - - - - -
' . esc_html( $tag['name'] ) . ''; // phpcs:ignore Generic.ControlStructures.InlineControlStructure.NotAllowed ?>' . esc_html( zeroBSCRM_prettifyLongInts($tag['count']) ) . ''; ?>
typeInt = $typeInt; + $this->postType = $zbs->DAL->typeCPT( $typeInt ); + $this->metaboxID = 'zerobs-' . $zbs->DAL->objTypeKey( $typeInt ) . '-tags-edit'; + $this->metaboxTitle = __( $zbs->DAL->typeStr( $typeInt ) . ' Tags', 'zero-bs-crm' ); + $this->metaboxScreen = 'zerobs_edit_tags'; // we can use anything here as is now using our func + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + // headless! + $this->headless = true; + + // call this + $this->initMetabox(); + } + + public function html( $contact, $metabox ) { + + global $zbs; + + // Get all tags + $tags = $zbs->DAL->getTagsForObjType( + array( + + 'objtypeid' => $this->typeInt, + 'excludeEmpty' => false, + 'withCount' => true, + 'ignoreowner' => true, + // sort + 'sortByField' => 'tagcount', + 'sortOrder' => 'DESC', + + ) + ); + + // pre-inject some potential js errors :) + ?>
+ +
+ + + + + + + */ ?> + + + + + + 0 ) { + foreach ( $tags as $tag ) { + + $link = jpcrm_esc_link( 'listtagged', -1, $this->postType, -1, $tag['id'] ); + ?> + + + + */ ?> + + + + + +
+ ' . esc_html( $tag['name'] ) . ''; + } + ?> + + + + ' . esc_html( zeroBSCRM_prettifyLongInts( $tag['count'] ) ) . '';} + ?> + + +
+ + + typeInt = $typeInt; // until db2 ZBS_TYPE_CONTACT; - $this->postType = $zbs->DAL->typeCPT($typeInt); - $this->metaboxID = 'zerobs-'.$zbs->DAL->objTypeKey($typeInt).'-tags'; - $this->metaboxTitle = __('Add '.$zbs->DAL->typeStr($typeInt).' Tags',"zero-bs-crm"); - $this->metaboxScreen = 'zerobs_edit_tags'; // we can use anything here as is now using our func - $this->metaboxArea = 'side'; - $this->metaboxLocation = 'high'; + global $zbs; - // call this - $this->initMetabox(); + $this->typeInt = $typeInt; // until db2 ZBS_TYPE_CONTACT; + $this->postType = $zbs->DAL->typeCPT( $typeInt ); + $this->metaboxID = 'zerobs-' . $zbs->DAL->objTypeKey( $typeInt ) . '-tags'; + $this->metaboxTitle = __( 'Add ' . $zbs->DAL->typeStr( $typeInt ) . ' Tags', 'zero-bs-crm' ); + $this->metaboxScreen = 'zerobs_edit_tags'; // we can use anything here as is now using our func + $this->metaboxArea = 'side'; + $this->metaboxLocation = 'high'; - } + // call this + $this->initMetabox(); + } - // html + save dealt with by parent class :) - } + // html + save dealt with by parent class :) +} -/* ====================================================== - / Create Tags Box - ====================================================== */ +/* +====================================================== + / Create Tags Box + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Tags.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Tags.php index 838b0842f3b0..a84e8e4f8930 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Tags.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Tags.php @@ -1,5 +1,5 @@ -initMetabox(); - - } - - public function html( $obj, $metabox ) { - - global $zbs; - - $objid = -1; if (is_array($obj) && isset($obj['id'])) $objid = $obj['id']; - - // if any already against obj, don't suggest em below - $excludeIDs = false; - - // get tags ahead of time + only show if not empty :) - $tags = $zbs->DAL->getTagsForObjID(array('objtypeid'=>$this->objTypeID,'objid'=>$objid)); - - // Debug echo 'Tags for '.$objid.'/'.$this->objTypeID.':
'; print_r($tags); echo '
'; - // simplify :) - $tagsArr = array(); if (is_array($tags) && count($tags) > 0) foreach ($tags as $t){ - /* even simpler... - $tag = array( - 'id' => $t->term_id, - 'name' => $t->name - ); - $tagsArr[] = $tag;*/ - - //$tagsArr[] = $t->name; - $tagsArr[] = $t['name']; - - // exclude from suggestions: - if (!is_array($excludeIDs)) $excludeIDs = array(); - $excludeIDs[] = $t['id']; - - } - $tags = $tagsArr; - - ?>
-
- - + public $objTypeID = false; // child fills out e.g. ZBS_TYPE_CONTACT + public $showSuggestions = false; // show/hide tag suggestions + public $saveAutomatically = false; // if this is true, this'll automatically update the object via addUpdateTags - this is off by default as most objects save tags themselves as part of addUpdateWhatever so that IA hooks fire correctly + public $metaboxClasses = 'zbs-edit-tags-box-wrap'; // this allows us to globally apply styles in editview.css + + public function __construct( $plugin_file ) { + + // call this + $this->initMetabox(); + } + + public function html( $obj, $metabox ) { + + global $zbs; + + $objid = -1; + if ( is_array( $obj ) && isset( $obj['id'] ) ) { + $objid = $obj['id']; + } + + // if any already against obj, don't suggest em below + $excludeIDs = false; + + // get tags ahead of time + only show if not empty :) + $tags = $zbs->DAL->getTagsForObjID( + array( + 'objtypeid' => $this->objTypeID, + 'objid' => $objid, + ) + ); + + // Debug echo 'Tags for '.$objid.'/'.$this->objTypeID.':
'; print_r($tags); echo '
'; + // simplify :) + $tagsArr = array(); if ( is_array( $tags ) && count( $tags ) > 0 ) { + foreach ( $tags as $t ) { + /* + even simpler... + $tag = array( + 'id' => $t->term_id, + 'name' => $t->name + ); + $tagsArr[] = $tag;*/ + + // $tagsArr[] = $t->name; + $tagsArr[] = $t['name']; + + // exclude from suggestions: + if ( ! is_array( $excludeIDs ) ) { + $excludeIDs = array(); + } + $excludeIDs[] = $t['id']; + + } + } + $tags = $tagsArr; + + ?>
+ +
+
+ + -
-
- '; - - $tagIndex = array(); - - ?> -
- showSuggestions){ - - // Get top 20 tags, show top 5 + expand - $tagSuggestions = $zbs->DAL->getTagsForObjType(array( - - 'objtypeid'=>$this->objTypeID, - 'excludeEmpty'=>false, - 'excludeIDs' => $excludeIDs, // if any already against obj, don't suggest em - 'withCount'=>true, - 'ignoreowner' => true, - // sort - 'sortByField' => 'tagcount', - 'sortOrder' => 'DESC', - // amount - 'page' => 0, - 'perPage' => 25 - - )); - - /* ( - [id] => 4 - [objtype] => 1 - [name] => John - [slug] => john - [created] => 1527771665 - [lastupdated] => 1527771999 - [count] => 3 - ) - */ - if (is_array($tagSuggestions) && count($tagSuggestions) > 0){ ?> -
+ + +
+
+ + '; + + $tagIndex = array(); + + ?> +
+ showSuggestions ) { + + // Get top 20 tags, show top 5 + expand + $tagSuggestions = $zbs->DAL->getTagsForObjType( + array( + + 'objtypeid' => $this->objTypeID, + 'excludeEmpty' => false, + 'excludeIDs' => $excludeIDs, // if any already against obj, don't suggest em + 'withCount' => true, + 'ignoreowner' => true, + // sort + 'sortByField' => 'tagcount', + 'sortOrder' => 'DESC', + // amount + 'page' => 0, + 'perPage' => 25, + + ) + ); + + /* + ( + [id] => 4 + [objtype] => 1 + [name] => John + [slug] => john + [created] => 1527771665 + [lastupdated] => 1527771999 + [count] => 3 + ) + */ + if ( is_array( $tagSuggestions ) && count( $tagSuggestions ) > 0 ) { + ?> +
-
- + 5){ + if ( $suggestionIndx == 5 && count( $tagSuggestions ) > 5 ) { - ?>
-
+
+
+
- 5){ + if ( count( $tagSuggestions ) > 5 ) { - ?>
-
-
- -
- - ; - } + + saveAutomatically){ + // Note: Most objects save tags as part of their own addUpdate routines. + // so this now only fires where saveAutomatically = true + if ( $this->saveAutomatically ) { - // Save tags against objid - // NEEDS AN OBJTYPE SWITCH HERE :) - $potentialTags = zeroBSCRM_tags_retrieveFromPostBag(true,ZBS_TYPE_CONTACT); + // Save tags against objid + // NEEDS AN OBJTYPE SWITCH HERE :) + $potentialTags = zeroBSCRM_tags_retrieveFromPostBag( true, ZBS_TYPE_CONTACT ); - } // / if saveAutomatically + } // / if saveAutomatically - return $obj; - } + return $obj; + } } -/* ====================================================== - / Create Tags Box - ====================================================== */ - +/* +====================================================== + / Create Tags Box + ====================================================== */ // tag related function - retrieve tags from post -function zeroBSCRM_tags_retrieveFromPostBag($returnAsIDs = true,$objectTypeID=-1){ - - // - NOTE THIS REQ: - // final tags are passed via hidden inpt zbs-tag-list - // look for zeroBSCRMJS_buildTagsInput in js :) JSONs it - if (isset($_POST['zbs-tag-list']) && !empty($_POST['zbs-tag-list']) && $objectTypeID > 0){ - - global $zbs; - - // should be json - // doesn't need decoding (wp done?) - $potentialTags = json_decode(stripslashes($_POST['zbs-tag-list'])); - - // not sanitized at this point.. - if (is_array($potentialTags)){ - - $tags = array(); - - foreach ($potentialTags as $tag){ - - $cleanTag = trim(sanitize_text_field( $tag )); - if (!empty($cleanTag) && !in_array($cleanTag, $tags)) $tags[] = $cleanTag; - - } // / foreach tag - - if (!$returnAsIDs) - return $tags; - // returns as array(0=>'tag1') etc. - else { - - $tagIDs = array(); - - // cycle through + find - foreach ($tags as $tag){ - - $tagID = $zbs->DAL->getTag( -1, array( - 'objtype' => $objectTypeID, - 'name' => $tag, - 'onlyID' => true, - )); - - //echo 'looking for tag "'.$tag.'" got id '.$tagID.'!
'; - - if (!empty($tagID)) - $tagIDs[] = $tagID; - else { - - //create - $tagID = $zbs->DAL->addUpdateTag( - array( - 'data' => array( - 'objtype' => $objectTypeID, - 'name' => $tag, - ) - ) - ); - //add - if (!empty($tagID)) $tagIDs[] = $tagID; - - } - } - - return $tagIDs; - - } - - } // / if is array - - } // / post - - return array(); +function zeroBSCRM_tags_retrieveFromPostBag( $returnAsIDs = true, $objectTypeID = -1 ) { + + // - NOTE THIS REQ: + // final tags are passed via hidden inpt zbs-tag-list + // look for zeroBSCRMJS_buildTagsInput in js :) JSONs it + if ( isset( $_POST['zbs-tag-list'] ) && ! empty( $_POST['zbs-tag-list'] ) && $objectTypeID > 0 ) { + + global $zbs; + + // should be json + // doesn't need decoding (wp done?) + $potentialTags = json_decode( stripslashes( $_POST['zbs-tag-list'] ) ); + + // not sanitized at this point.. + if ( is_array( $potentialTags ) ) { + + $tags = array(); + + foreach ( $potentialTags as $tag ) { + + $cleanTag = trim( sanitize_text_field( $tag ) ); + if ( ! empty( $cleanTag ) && ! in_array( $cleanTag, $tags ) ) { + $tags[] = $cleanTag; + } + } // / foreach tag + + if ( ! $returnAsIDs ) { + return $tags; + } + // returns as array(0=>'tag1') etc. + else { + + $tagIDs = array(); + + // cycle through + find + foreach ( $tags as $tag ) { + + $tagID = $zbs->DAL->getTag( + -1, + array( + 'objtype' => $objectTypeID, + 'name' => $tag, + 'onlyID' => true, + ) + ); + + // echo 'looking for tag "'.$tag.'" got id '.$tagID.'!
'; + + if ( ! empty( $tagID ) ) { + $tagIDs[] = $tagID; + } else { + + // create + $tagID = $zbs->DAL->addUpdateTag( + array( + 'data' => array( + 'objtype' => $objectTypeID, + 'name' => $tag, + ), + ) + ); + // add + if ( ! empty( $tagID ) ) { + $tagIDs[] = $tagID; + } + } + } + + return $tagIDs; + + } + } // / if is array + + } // / post + + return array(); } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Tasks.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Tasks.php index 3b1e20371db2..3e974b0d95c1 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Tasks.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Tasks.php @@ -1,6 +1,5 @@ objType = 'event'; $this->metaboxID = 'zerobs-event-tags'; $this->metaboxTitle = __( 'Task Tags', 'zero-bs-crm' ); - $this->metaboxScreen = 'zbs-add-edit-event-edit'; //'zerobs_edit_contact'; // we can use anything here as is now using our func + $this->metaboxScreen = 'zbs-add-edit-event-edit'; // 'zerobs_edit_contact'; // we can use anything here as is now using our func $this->metaboxArea = 'side'; $this->metaboxLocation = 'low'; $this->showSuggestions = true; @@ -579,7 +578,7 @@ function zeroBSCRM_task_ui_assignment( $taskObject = array(), $taskID = -1 ) { $linked_cal = $zbs->DAL->meta( ZBS_TYPE_TASK, $taskID, $key = 'zbs_outlook_id', false ); // false = default here if ( $uid != $current_task_user_id ) { - //then it is LOCKED and cannot be changed to another owner? + // then it is LOCKED and cannot be changed to another owner? } // get potential owners @@ -636,7 +635,7 @@ function zeroBSCRM_task_ui_for( $taskObject = array() ) { global $zbs; $html = "
" . __( 'Contact', 'zero-bs-crm' ) . '
'; - //need UI for selecting who the task is for (company, then contaxt) + // need UI for selecting who the task is for (company, then contaxt) $custName = ''; $custID = ''; @@ -676,7 +675,7 @@ function zeroBSCRM_task_ui_for_co( $taskObject = array() ) { $html .= "
" . jpcrm_label_company() . '
'; - //need UI for selecting who the task is for (company, then contact) + // need UI for selecting who the task is for (company, then contact) $co_name = ''; $co_id = ''; @@ -770,7 +769,7 @@ function zeroBSCRM_task_ui_reminders( $taskObject = array(), $taskID = -1 ) { $show = false; // v3.0 + this is differently stored: - //if (isset($taskObject['notify_crm'])) $show = $taskObject['notify_crm']; + // if (isset($taskObject['notify_crm'])) $show = $taskObject['notify_crm']; if ( isset( $taskObject['reminders'] ) && is_array( $taskObject['reminders'] ) ) { // eventually diff time reminders will be in this array, for v3.0 we only have 24h reminders @@ -807,7 +806,7 @@ function zeroBSCRM_task_ui_reminders( $taskObject = array(), $taskID = -1 ) { $html .= ' checked="checked"'; } $html .= "/>
'; - // $html .= "" .__('Add more reminders', 'zero-bs-crm') . ""; + // $html .= "" .__('Add more reminders', 'zero-bs-crm') . ""; $html .= '
'; #} Better reminders in Calendar Pro :-) diff --git a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Transactions.php b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Transactions.php index e49d22564c7b..ade3dcdda2df 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Transactions.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.MetaBoxes3.Transactions.php @@ -1,5 +1,5 @@ -objType = 'transaction'; - $this->metaboxID = 'zerobs-transaction-edit'; - $this->metaboxTitle = __('Transaction Information','zero-bs-crm'); // will be headless anyhow - $this->headless = true; - $this->metaboxScreen = 'zbs-add-edit-transaction-edit'; - $this->metaboxArea = 'normal'; - $this->metaboxLocation = 'high'; - $this->saveOrder = 1; - $this->capabilities = array( - - 'can_hide' => false, // can be hidden - 'areas' => array('normal'), // areas can be dragged to - normal side = only areas currently - 'can_accept_tabs' => true, // can/can't accept tabs onto it - 'can_become_tab' => false, // can be added as tab - 'can_minimise' => true, // can be minimised - 'can_move' => true // can be moved + // external sources + $zeroBS__Metabox_ExtSource = new zeroBS__Metabox_ExtSource( __FILE__, 'transaction', 'zbs-add-edit-transaction-edit' ); +} - ); + add_action( 'admin_init', 'zeroBSCRM_TransactionsMetaboxSetup' ); - // call this - $this->initMetabox(); +/* +====================================================== + / Init Func + ====================================================== */ - } +/* +====================================================== + Transaction Metabox + ====================================================== */ - public function html( $transaction, $metabox ) { +class zeroBS__Metabox_Transaction extends zeroBS__Metabox { - // localise ID - $transactionID = -1; if (is_array($transaction) && isset($transaction['id'])) $transactionID = (int)$transaction['id']; + // this is for catching 'new' transactions + private $newRecordNeedsRedir = false; - // if new + $zbsObjDataPrefill passed, use that instead of loaded trans. - if ($transactionID == -1){ - global $zbsObjDataPrefill; - $transaction = $zbsObjDataPrefill; - } + public function __construct( $plugin_file ) { - global $zbs; + // set these + $this->objType = 'transaction'; + $this->metaboxID = 'zerobs-transaction-edit'; + $this->metaboxTitle = __( 'Transaction Information', 'zero-bs-crm' ); // will be headless anyhow + $this->headless = true; + $this->metaboxScreen = 'zbs-add-edit-transaction-edit'; + $this->metaboxArea = 'normal'; + $this->metaboxLocation = 'high'; + $this->saveOrder = 1; + $this->capabilities = array( + 'can_hide' => false, // can be hidden + 'areas' => array( 'normal' ), // areas can be dragged to - normal side = only areas currently + 'can_accept_tabs' => true, // can/can't accept tabs onto it + 'can_become_tab' => false, // can be added as tab + 'can_minimise' => true, // can be minimised + 'can_move' => true, // can be moved - #} Prefill ID and OBJ are added to the #zbs_invoice to aid in prefilling the data (when drawn with JS) - $prefill_id = -1; $prefill_obj = -1; $prefill_email = ''; - if (isset($_GET['zbsprefillcust']) && !empty($_GET['zbsprefillcust'])){ - $prefill_id = (int)$_GET['zbsprefillcust']; - $prefill_obj = ZBS_TYPE_CONTACT; - $prefill_email = zeroBS_customerEmail($prefill_id); - } - if (isset($_GET['zbsprefillco']) && !empty($_GET['zbsprefillco'])){ - $prefill_id = (int)$_GET['zbsprefillco']; - $prefill_obj = ZBS_TYPE_COMPANY; - $prefill_email = zeroBS_companyEmail($prefill_id); - } + ); - // DAL2 legacy, patched through - $contactID = -1; if (is_array($transaction) && isset($transaction['contact']) && is_array($transaction['contact']) && count($transaction['contact']) > 0) $contactID = $transaction['contact'][0]['id']; - $companyID = -1; if (is_array($transaction) && isset($transaction['company']) && is_array($transaction['company']) && count($transaction['company']) > 0) $companyID = $transaction['company'][0]['id']; - $contactName = ''; $companyName = ''; - if ($contactID > 0) $contactName = $zbs->DAL->contacts->getContactNameWithFallback( $contactID ); - if (empty($contactName) || $contactName == -1) $contactName = ''; - if (!empty($companyID) && $companyID > 0){ - $companyName = $zbs->DAL->companies->getCompanyNameEtc($companyID); - if (empty($companyName)) $companyName = jpcrm_label_company().' #'.$companyID; - } + // call this + $this->initMetabox(); + } - // prefill if not assigned: - if ($contactID == -1 && $companyID == -1){ + public function html( $transaction, $metabox ) { + + // localise ID + $transactionID = -1; + if ( is_array( $transaction ) && isset( $transaction['id'] ) ) { + $transactionID = (int) $transaction['id']; + } + + // if new + $zbsObjDataPrefill passed, use that instead of loaded trans. + if ( $transactionID == -1 ) { + global $zbsObjDataPrefill; + $transaction = $zbsObjDataPrefill; + } + + global $zbs; + + #} Prefill ID and OBJ are added to the #zbs_invoice to aid in prefilling the data (when drawn with JS) + $prefill_id = -1; + $prefill_obj = -1; + $prefill_email = ''; + if ( isset( $_GET['zbsprefillcust'] ) && ! empty( $_GET['zbsprefillcust'] ) ) { + $prefill_id = (int) $_GET['zbsprefillcust']; + $prefill_obj = ZBS_TYPE_CONTACT; + $prefill_email = zeroBS_customerEmail( $prefill_id ); + } + if ( isset( $_GET['zbsprefillco'] ) && ! empty( $_GET['zbsprefillco'] ) ) { + $prefill_id = (int) $_GET['zbsprefillco']; + $prefill_obj = ZBS_TYPE_COMPANY; + $prefill_email = zeroBS_companyEmail( $prefill_id ); + } + + // DAL2 legacy, patched through + $contactID = -1; + if ( is_array( $transaction ) && isset( $transaction['contact'] ) && is_array( $transaction['contact'] ) && count( $transaction['contact'] ) > 0 ) { + $contactID = $transaction['contact'][0]['id']; + } + $companyID = -1; + if ( is_array( $transaction ) && isset( $transaction['company'] ) && is_array( $transaction['company'] ) && count( $transaction['company'] ) > 0 ) { + $companyID = $transaction['company'][0]['id']; + } + $contactName = ''; + $companyName = ''; + if ( $contactID > 0 ) { + $contactName = $zbs->DAL->contacts->getContactNameWithFallback( $contactID ); + } + if ( empty( $contactName ) || $contactName == -1 ) { + $contactName = ''; + } + if ( ! empty( $companyID ) && $companyID > 0 ) { + $companyName = $zbs->DAL->companies->getCompanyNameEtc( $companyID ); + if ( empty( $companyName ) ) { + $companyName = jpcrm_label_company() . ' #' . $companyID; + } + } - switch ($prefill_obj){ + // prefill if not assigned: + if ( $contactID == -1 && $companyID == -1 ) { - case ZBS_TYPE_CONTACT: + switch ( $prefill_obj ) { - if ($prefill_id > 0){ - - // dump into contactID etc. - $contactID = $prefill_id; - $contactName = $zbs->DAL->contacts->getContactNameWithFallback( $contactID ); + case ZBS_TYPE_CONTACT: + if ( $prefill_id > 0 ) { - } + // dump into contactID etc. + $contactID = $prefill_id; + $contactName = $zbs->DAL->contacts->getContactNameWithFallback( $contactID ); - break; + } - case ZBS_TYPE_COMPANY: + break; - if ($prefill_id > 0){ - - // dump into contactID etc. - $companyID = $prefill_id; - $companyName = $zbs->DAL->companies->getCompanyNameEtc($companyID); - if (empty($companyName)) $companyName = jpcrm_label_company().' #'.$companyID; + case ZBS_TYPE_COMPANY: + if ( $prefill_id > 0 ) { - } + // dump into contactID etc. + $companyID = $prefill_id; + $companyName = $zbs->DAL->companies->getCompanyNameEtc( $companyID ); + if ( empty( $companyName ) ) { + $companyName = jpcrm_label_company() . ' #' . $companyID; + } + } + break; - break; + } + } - } + ?> + + '; } - ?> - - '; - - ?>
@@ -167,31 +179,31 @@ public function html( $transaction, $metabox ) {
- - - - - + + + +
- -
- + // mikes inv selector + ?>
-
-
+ ?> + + + -
+ + + + 0) ? array($zbsTransactionContact) : array(); - $zbsTransactionCompany = (int)sanitize_text_field($_POST['zbsct_company']); - $transaction['companies'] = ($zbsTransactionCompany > 0) ? array($zbsTransactionCompany) : array(); - + $date = jpcrm_datetime_post_keys_to_uts( 'zbst_date' ); + $transaction['date'] = empty( $date ) ? time() : $date; - #} Invoice allocation: - $transaction['invoice_id'] = ''; if(isset($_POST['invoice_id'])) $transaction['invoice_id'] = (int)sanitize_text_field($_POST["invoice_id"]); + $date_paid = jpcrm_datetime_post_keys_to_uts( 'zbst_date_paid' ); + $transaction['date_paid'] = empty( $date_paid ) ? $transaction['date'] : $date_paid; + $date_completed = jpcrm_datetime_post_keys_to_uts( 'zbst_date_completed' ); + $transaction['date_completed'] = empty( $date_completed ) ? $transaction['date'] : $date_completed; - // add/update - $addUpdateReturn = $zbs->DAL->transactions->addUpdateTransaction(array( + // currency wasn't set when storing manually too + $transaction['currency'] = zeroBSCRM_getCurrencyStr(); - 'id' => $transactionID, - 'data' => $transaction, - 'limitedFields' => -1, + // assignments + $zbsTransactionContact = (int) sanitize_text_field( $_POST['customer'] ); + $transaction['contacts'] = ( $zbsTransactionContact > 0 ) ? array( $zbsTransactionContact ) : array(); + $zbsTransactionCompany = (int) sanitize_text_field( $_POST['zbsct_company'] ); + $transaction['companies'] = ( $zbsTransactionCompany > 0 ) ? array( $zbsTransactionCompany ) : array(); - )); + #} Invoice allocation: + $transaction['invoice_id'] = ''; + if ( isset( $_POST['invoice_id'] ) ) { + $transaction['invoice_id'] = (int) sanitize_text_field( $_POST['invoice_id'] ); + } - // Note: For NEW objs, we make sure a global is set here, that other update funcs can catch - // ... so it's essential this one runs first! - // this is managed in the metabox Class :) - if ($transactionID == -1 && !empty($addUpdateReturn) && $addUpdateReturn != -1) { - - $transactionID = $addUpdateReturn; - global $zbsJustInsertedMetaboxID; $zbsJustInsertedMetaboxID = $transactionID; + // add/update + $addUpdateReturn = $zbs->DAL->transactions->addUpdateTransaction( + array( - // set this so it redirs - $this->newRecordNeedsRedir = true; - } + 'id' => $transactionID, + 'data' => $transaction, + 'limitedFields' => -1, - // success? - if ($addUpdateReturn != -1 && $addUpdateReturn > 0){ + ) + ); - // Update Msg - // this adds an update message which'll go out ahead of any content - // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); - // This adds to edit page - $this->updateMessage(); + // Note: For NEW objs, we make sure a global is set here, that other update funcs can catch + // ... so it's essential this one runs first! + // this is managed in the metabox Class :) + if ( $transactionID == -1 && ! empty( $addUpdateReturn ) && $addUpdateReturn != -1 ) { - // catch any non-critical messages - $nonCriticalMessages = $zbs->DAL->getErrors(ZBS_TYPE_TRANSACTION); - if (is_array($nonCriticalMessages) && count($nonCriticalMessages) > 0) $this->dalNoticeMessage($nonCriticalMessages); + $transactionID = $addUpdateReturn; + global $zbsJustInsertedMetaboxID; + $zbsJustInsertedMetaboxID = $transactionID; + // set this so it redirs + $this->newRecordNeedsRedir = true; + } - } else { + // success? + if ( $addUpdateReturn != -1 && $addUpdateReturn > 0 ) { - // fail somehow - $failMessages = $zbs->DAL->getErrors(ZBS_TYPE_TRANSACTION); + // Update Msg + // this adds an update message which'll go out ahead of any content + // This adds to metabox: $this->updateMessages['update'] = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',__('Contact Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); + // This adds to edit page + $this->updateMessage(); - // show msg (retrieved from DAL err stack) - if (is_array($failMessages) && count($failMessages) > 0) - $this->dalErrorMessage($failMessages); - else - $this->dalErrorMessage(array(__('Insert/Update Failed with general error','zero-bs-crm'))); + // catch any non-critical messages + $nonCriticalMessages = $zbs->DAL->getErrors( ZBS_TYPE_TRANSACTION ); + if ( is_array( $nonCriticalMessages ) && count( $nonCriticalMessages ) > 0 ) { + $this->dalNoticeMessage( $nonCriticalMessages ); + } + } else { - // pass the pre-fill: - global $zbsObjDataPrefill; $zbsObjDataPrefill = $transaction; + // fail somehow + $failMessages = $zbs->DAL->getErrors( ZBS_TYPE_TRANSACTION ); - - } + // show msg (retrieved from DAL err stack) + if ( is_array( $failMessages ) && count( $failMessages ) > 0 ) { + $this->dalErrorMessage( $failMessages ); + } else { + $this->dalErrorMessage( array( __( 'Insert/Update Failed with general error', 'zero-bs-crm' ) ) ); + } - + // pass the pre-fill: + global $zbsObjDataPrefill; + $zbsObjDataPrefill = $transaction; - } + } + } - return $transaction; - } + return $transaction; + } - // This catches 'new' contacts + redirs to right url - public function post_save_data($objID,$obj){ + // This catches 'new' contacts + redirs to right url + public function post_save_data( $objID, $obj ) { - if ($this->newRecordNeedsRedir){ + if ( $this->newRecordNeedsRedir ) { - global $zbsJustInsertedMetaboxID; - if (!empty($zbsJustInsertedMetaboxID) && $zbsJustInsertedMetaboxID > 0){ + global $zbsJustInsertedMetaboxID; + if ( ! empty( $zbsJustInsertedMetaboxID ) && $zbsJustInsertedMetaboxID > 0 ) { - // redir - wp_redirect( jpcrm_esc_link('edit',$zbsJustInsertedMetaboxID,$this->objType) ); + // redir + wp_redirect( jpcrm_esc_link( 'edit', $zbsJustInsertedMetaboxID, $this->objType ) ); exit( 0 ); - } - - } - - } - - public function updateMessage(){ - - global $zbs; - - // zbs-not-urgent means it'll auto hide after 1.5s - // genericified from DAL3.0 - $msg = zeroBSCRM_UI2_messageHTML('info olive mini zbs-not-urgent',$zbs->DAL->typeStr($zbs->DAL->objTypeKey($this->objType)).' '.__('Updated',"zero-bs-crm"),'','address book outline','contactUpdated'); + } + } + } - $zbs->pageMessages[] = $msg; + public function updateMessage() { - } - } + global $zbs; + // zbs-not-urgent means it'll auto hide after 1.5s + // genericified from DAL3.0 + $msg = zeroBSCRM_UI2_messageHTML( 'info olive mini zbs-not-urgent', $zbs->DAL->typeStr( $zbs->DAL->objTypeKey( $this->objType ) ) . ' ' . __( 'Updated', 'zero-bs-crm' ), '', 'address book outline', 'contactUpdated' ); -/* ====================================================== - / Transaction Metabox - ====================================================== */ + $zbs->pageMessages[] = $msg; + } +} +/* +====================================================== + / Transaction Metabox + ====================================================== */ -/* ====================================================== - Create Tags Box - ====================================================== */ +/* +====================================================== + Create Tags Box + ====================================================== */ // phpcs:ignore class zeroBS__Metabox_TransactionTags extends zeroBS__Metabox_Tags { @@ -583,14 +595,15 @@ public function __construct( $plugin_file ) { // phpcs:ignore // html + save dealt with by parent class :) } -/* ====================================================== - / Create Tags Box - ====================================================== */ - +/* +====================================================== + / Create Tags Box + ====================================================== */ -/* ====================================================== - Transaction Actions Metabox - ====================================================== */ +/* +====================================================== + Transaction Actions Metabox + ====================================================== */ // phpcs:ignore class zeroBS__Metabox_TransactionActions extends zeroBS__Metabox { diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Migrations.php b/projects/plugins/crm/includes/ZeroBSCRM.Migrations.php index e21d29b58d7e..0bf57bdd4d5c 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Migrations.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Migrations.php @@ -1,5 +1,5 @@ array( 'wp_loaded' ), ); - // mark's a migration complete -function zeroBSCRM_migrations_markComplete($migrationKey=-1,$logObj=false){ +function zeroBSCRM_migrations_markComplete( $migrationKey = -1, $logObj = false ) { global $zeroBSCRM_migrations; - if (!empty($migrationKey) && in_array($migrationKey, $zeroBSCRM_migrations)) { + if ( ! empty( $migrationKey ) && in_array( $migrationKey, $zeroBSCRM_migrations ) ) { - $completedMigrations = zeroBSCRM_migrations_getCompleted(); + $completedMigrations = zeroBSCRM_migrations_getCompleted(); $completedMigrations[] = $migrationKey; // we're using wp options because they're reliable OUTSIDE of the scope of our settings model - // ... which has changed through versions + // ... which has changed through versions // the separation here is key, at 2.88 WH discovered much re-running + pain due to this. // stick to a separate migration system (away from zbssettings) - update_option('zbsmigrations',$completedMigrations, false); + update_option( 'zbsmigrations', $completedMigrations, false ); // log opt? - update_option('zbsmigration'.$migrationKey,array('completed'=>time(),'meta'=>$logObj), false); + update_option( + 'zbsmigration' . $migrationKey, + array( + 'completed' => time(), + 'meta' => $logObj, + ), + false + ); } } // gets the list of completed migrations -function zeroBSCRM_migrations_getCompleted(){ +function zeroBSCRM_migrations_getCompleted() { // we're using wp options because they're reliable OUTSIDE of the scope of our settings model - // ... which has changed through versions + // ... which has changed through versions // the separation here is key, at 2.88 WH discovered much re-running + pain due to this. // stick to a separate migration system (away from zbssettings) // BUT WAIT! hilariously, for those who already have finished migrations, this'll re-run them // ... so here we 'MIGRATE' the migrations :o ffs - global $zbs; $migrations = $zbs->settings->get('migrations'); if (isset($migrations) && is_array($migrations) && count($migrations) > 0) { - - $existingMigrationsMigration = get_option( 'zbsmigrationsdal', -1); + global $zbs; + $migrations = $zbs->settings->get( 'migrations' ); if ( isset( $migrations ) && is_array( $migrations ) && count( $migrations ) > 0 ) { + + $existingMigrationsMigration = get_option( 'zbsmigrationsdal', -1 ); - if ($existingMigrationsMigration == -1){ + if ( $existingMigrationsMigration == -1 ) { // copy over + // to stop this ever rerunning + confusing things, we set an option to say migrated the migrations, LOL - update_option('zbsmigrations',$migrations, false); - update_option('zbsmigrationsdal',2, false); + update_option( 'zbsmigrations', $migrations, false ); + update_option( 'zbsmigrationsdal', 2, false ); } } // normal return return get_option( 'zbsmigrations', array() ); - } // gets details on a migration -function jpcrm_migrations_get_migration($migrationKey=''){ +function jpcrm_migrations_get_migration( $migrationKey = '' ) { // we're using wp options because they're reliable OUTSIDE of the scope of our settings model - // ... which has changed through versions + // ... which has changed through versions // the separation here is key, at 2.88 WH discovered much re-running + pain due to this. // stick to a separate migration system (away from zbssettings) - $finished = false; $migrations = zeroBSCRM_migrations_getCompleted(); if (in_array($migrationKey,$migrations)) $finished = true; - - return array($finished,get_option('zbsmigration'.$migrationKey,false)); + $finished = false; + $migrations = zeroBSCRM_migrations_getCompleted(); + if ( in_array( $migrationKey, $migrations ) ) { + $finished = true; + } + return array( $finished, get_option( 'zbsmigration' . $migrationKey, false ) ); } -function zeroBSCRM_migrations_run( $settingsArr = false, $run_at = 'init' ){ +function zeroBSCRM_migrations_run( $settingsArr = false, $run_at = 'init' ) { - global $zeroBSCRM_migrations,$zeroBSCRM_migrations_requirements; + global $zeroBSCRM_migrations, $zeroBSCRM_migrations_requirements; - // catch migration block removal (can be run from system status): - if (current_user_can('admin_zerobs_manage_options') && isset($_GET['resetmigrationblock']) && wp_verify_nonce( $_GET['_wpnonce'], 'resetmigrationblock' ) ){ + // catch migration block removal (can be run from system status): + if ( current_user_can( 'admin_zerobs_manage_options' ) && isset( $_GET['resetmigrationblock'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'resetmigrationblock' ) ) { - // unblock migration blocks - delete_option('zbsmigrationpreloadcatch'); - delete_option('zbsmigrationblockerrors'); + // unblock migration blocks + delete_option( 'zbsmigrationpreloadcatch' ); + delete_option( 'zbsmigrationblockerrors' ); - // flag - $migrationBlocksRemoved = true; - } + // flag + $migrationBlocksRemoved = true; + } #} Check if we've been stumped by blocking errs, and STOP migrating if so - $blockingErrs = get_option( 'zbsmigrationblockerrors', false); - if ($blockingErrs !== false && !empty($blockingErrs)) return false; + $blockingErrs = get_option( 'zbsmigrationblockerrors', false ); + if ( $blockingErrs !== false && ! empty( $blockingErrs ) ) { + return false; + } #} load migrated list if not loaded $migratedAlreadyArr = zeroBSCRM_migrations_getCompleted(); @@ -136,107 +148,114 @@ function zeroBSCRM_migrations_run( $settingsArr = false, $run_at = 'init' ){ $migrationRunCount = 0; #} cycle through any migrations + fire if not fired. - if (count($zeroBSCRM_migrations) > 0) foreach ($zeroBSCRM_migrations as $migration){ + if ( count( $zeroBSCRM_migrations ) > 0 ) { + foreach ( $zeroBSCRM_migrations as $migration ) { - if (!in_array($migration,$migratedAlreadyArr) && function_exists('zeroBSCRM_migration_'.$migration)) { + if ( ! in_array( $migration, $migratedAlreadyArr ) && function_exists( 'zeroBSCRM_migration_' . $migration ) ) { - $run = true; + $run = true; - // check reached state - if ( isset( $zeroBSCRM_migrations_requirements[$migration] ) ){ + // check reached state + if ( isset( $zeroBSCRM_migrations_requirements[ $migration ] ) ) { - // 'preload' requirement means this migration needs to run AFTER a reload AFTER the previous migration - // ... so if preload here, we kill this loop, if prev migrations have run - if ( in_array( 'preload', $zeroBSCRM_migrations_requirements[$migration]) && $migrationRunCount > 0 ){ + // 'preload' requirement means this migration needs to run AFTER a reload AFTER the previous migration + // ... so if preload here, we kill this loop, if prev migrations have run + if ( in_array( 'preload', $zeroBSCRM_migrations_requirements[ $migration ] ) && $migrationRunCount > 0 ) { - // ... as a catch to stop infinite reloads, we check whether more than 3 of these have run in a row, and we stop that. - $previousAttempts = get_option( 'zbsmigrationpreloadcatch', array()); - if (!is_array($previousAttempts)) $previousAttempts = array(); - if (!isset($previousAttempts[$migration])) $previousAttempts[$migration] = 1; - if ($previousAttempts[$migration] < 5){ + // ... as a catch to stop infinite reloads, we check whether more than 3 of these have run in a row, and we stop that. + $previousAttempts = get_option( 'zbsmigrationpreloadcatch', array() ); + if ( ! is_array( $previousAttempts ) ) { + $previousAttempts = array(); + } + if ( ! isset( $previousAttempts[ $migration ] ) ) { + $previousAttempts[ $migration ] = 1; + } + if ( $previousAttempts[ $migration ] < 5 ) { - // update count - $previousAttempts[$migration]++; - update_option('zbsmigrationpreloadcatch', $previousAttempts, false); + // update count + ++$previousAttempts[ $migration ]; + update_option( 'zbsmigrationpreloadcatch', $previousAttempts, false ); - // stop running migrations, reload the page - header("Refresh:0"); - exit( 0 ); + // stop running migrations, reload the page + header( 'Refresh:0' ); + exit( 0 ); - } else { + } else { - // set a global which'll show up on systemstatus if this state occurs. - update_option('zbsmigrationblockerrors', $migration, false); + // set a global which'll show up on systemstatus if this state occurs. + update_option( 'zbsmigrationblockerrors', $migration, false ); - // expose an error that the world's about to rupture - add_action('after-zerobscrm-admin-init','zeroBSCRM_adminNotices_majorMigrationError'); - add_action( 'admin_notices', 'zeroBSCRM_adminNotices_majorMigrationError' ); + // expose an error that the world's about to rupture + add_action( 'after-zerobscrm-admin-init', 'zeroBSCRM_adminNotices_majorMigrationError' ); + add_action( 'admin_notices', 'zeroBSCRM_adminNotices_majorMigrationError' ); + } } - } + // assume func + foreach ( $zeroBSCRM_migrations_requirements[ $migration ] as $check ) { - // assume func - foreach ($zeroBSCRM_migrations_requirements[$migration] as $check){ - - // skip 'preload', dealt with above - // skip 'wp_loaded', dealt with in second run - if ( $check !== 'preload' && $check !== 'wp_loaded' ){ - - $checkFuncName = 'zeroBSCRM_migrations_checks_'.$check; - if (!call_user_func($checkFuncName)) $run = false; + // skip 'preload', dealt with above + // skip 'wp_loaded', dealt with in second run + if ( $check !== 'preload' && $check !== 'wp_loaded' ) { + $checkFuncName = 'zeroBSCRM_migrations_checks_' . $check; + if ( ! call_user_func( $checkFuncName ) ) { + $run = false; + } + } } - } - - // wp_loaded - if ( in_array( 'wp_loaded', $zeroBSCRM_migrations_requirements[$migration] ) ){ - $run = false; + // wp_loaded + if ( in_array( 'wp_loaded', $zeroBSCRM_migrations_requirements[ $migration ] ) ) { - if ( $run_at == 'wp_loaded' ){ - $run = true; - } + $run = false; + if ( $run_at == 'wp_loaded' ) { + $run = true; + } + } } - } + // go + if ( $run ) { - // go - if ($run) { + // run migration + call_user_func( 'zeroBSCRM_migration_' . $migration ); - // run migration - call_user_func('zeroBSCRM_migration_'.$migration); - - // update count - $migrationRunCount++; + // update count + ++$migrationRunCount; + } } } - } - } -function zeroBSCRM_migrations_checks_postsettings(){ +function zeroBSCRM_migrations_checks_postsettings() { global $zbs; - /* didn't work: + /* + didn't work: if (isset($zbs->settings) && method_exists($zbs->settings,'get')){ $possiblyInstalled = $zbs->settings->get('settingsinstalled',true); if (isset($possiblyInstalled) && $possiblyInstalled > 0) return true; } */ // HARD DB settings check try { - $potentialDBSetting = $zbs->DAL->getSetting(array('key' => 'settingsinstalled','fullDetails' => false)); + $potentialDBSetting = $zbs->DAL->getSetting( + array( + 'key' => 'settingsinstalled', + 'fullDetails' => false, + ) + ); - if (isset($potentialDBSetting) && $potentialDBSetting > 0) { + if ( isset( $potentialDBSetting ) && $potentialDBSetting > 0 ) { return true; } - - } catch (Exception $e){ + } catch ( Exception $e ) { } @@ -244,47 +263,43 @@ function zeroBSCRM_migrations_checks_postsettings(){ } // general migration mechanism error -function zeroBSCRM_adminNotices_majorMigrationError(){ +function zeroBSCRM_adminNotices_majorMigrationError() { - //pop in a Notify Me Notification here instead....? - if (get_current_user_id() > 0){ + // pop in a Notify Me Notification here instead....? + if ( get_current_user_id() > 0 ) { - // already sent? - $msgSent = get_transient('zbs-migration-general-errors'); - if (!$msgSent){ + // already sent? + $msgSent = get_transient( 'zbs-migration-general-errors' ); + if ( ! $msgSent ) { - zeroBSCRM_notifyme_insert_notification(get_current_user_id(), -999, -1, 'migration.blocked.errors','migration.blocked.errors'); - set_transient( 'zbs-migration-general-errors', 20, 24 * 7 * HOUR_IN_SECONDS ); - - } + zeroBSCRM_notifyme_insert_notification( get_current_user_id(), -999, -1, 'migration.blocked.errors', 'migration.blocked.errors' ); + set_transient( 'zbs-migration-general-errors', 20, 24 * 7 * HOUR_IN_SECONDS ); + } } - } -/* ====================================================== +/* +====================================================== / MIGRATION FUNCS - ====================================================== */ + ====================================================== */ - - -/* ====================================================== +/* +====================================================== MIGRATIONS - ====================================================== */ + ====================================================== */ /* * Migration 2.88 - build client portal page (moved to shortcodes) if using */ - function zeroBSCRM_migration_288(){ - - global $zbs; +function zeroBSCRM_migration_288() { - zeroBSCRM_portal_checkCreatePage(); - - zeroBSCRM_migrations_markComplete('288',array('updated'=>'1')); + global $zbs; - } + zeroBSCRM_portal_checkCreatePage(); + zeroBSCRM_migrations_markComplete( '288', array( 'updated' => '1' ) ); +} /* * Migration 2.4 - Refresh user roles @@ -292,361 +307,352 @@ function zeroBSCRM_migration_288(){ * for v5 we combined these, though in time the need for this method of install should be done away with * Previously, migrations: 2.96.3, 2.96.4, 2.96.6, 2.97.4, 4.0.7, 4.0.8 */ - function zeroBSCRM_migration_2963(){ - - global $zbs, $wpdb, $ZBSCRM_t; - - #} Check + create - zeroBSCRM_checkTablesExist(); - - #} Make the DB emails... - zeroBSCRM_populateEmailTemplateList(); - - - // ===== Previously: Migration 2.96.3 - adds new template for 'client portal pw reset' - - #} default is admin email and CRM name - //now all done via zeroBSCRM_mailDelivery_defaultFromname - $from_name = zeroBSCRM_mailDelivery_defaultFromname(); - - /* This wasn't used in end, switched to default mail delivery opt - $from_address = zeroBSCRM_mailDelivery_defaultEmail();; //default WordPress admin email ? - $reply_to = ''; - $cc = ''; */ - $deliveryMethod = zeroBSCRM_getMailDeliveryDefault(); - - $ID = 6; - $reply_to = ''; - $cc = ''; - $bcc = ''; - - #} The email stuff... - $subject = __("Your Client Portal Password", 'zero-bs-crm'); - $content = zeroBSCRM_mail_retrieveDefaultBodyTemplate('clientportalpwreset'); - $active = 1; //1 = true.. - if(zeroBSCRM_mailTemplate_exists($ID) == 0){ - $content = zeroBSCRM_mailTemplate_processEmailHTML($content); - //zeroBSCRM_insertEmailTemplate($ID,$from_name,$from_address,$reply_to,$cc,$bcc,$subject,$content,$active); - zeroBSCRM_insertEmailTemplate($ID,$deliveryMethod,$bcc,$subject,$content,$active); - } +function zeroBSCRM_migration_2963() { - // ===== / Previously: Migration 2.96.3 - - - // ===== Previously: last one hadn't got the html file, this ADDS file proper :) - - #} default is admin email and CRM name - //now all done via zeroBSCRM_mailDelivery_defaultFromname - $from_name = zeroBSCRM_mailDelivery_defaultFromname(); - - /* This wasn't used in end, switched to default mail delivery opt - $from_address = zeroBSCRM_mailDelivery_defaultEmail();; //default WordPress admin email ? - $reply_to = ''; - $cc = ''; */ - $deliveryMethod = zeroBSCRM_getMailDeliveryDefault(); - - $ID = 6; - $reply_to = ''; - $cc = ''; - $bcc = ''; - - // BRUTAL DELETE old one - $wpdb->delete( $ZBSCRM_t['system_mail_templates'], array( 'zbsmail_id' => $ID ) ); - - #} The email stuff... - $subject = __("Your Client Portal Password", 'zero-bs-crm'); - $content = zeroBSCRM_mail_retrieveDefaultBodyTemplate('clientportalpwreset'); - - $active = 1; //1 = true.. - if(zeroBSCRM_mailTemplate_exists($ID) == 0){ - $content = zeroBSCRM_mailTemplate_processEmailHTML($content); - //zeroBSCRM_insertEmailTemplate($ID,$from_name,$from_address,$reply_to,$cc,$bcc,$subject,$content,$active); - zeroBSCRM_insertEmailTemplate($ID,$deliveryMethod,$bcc,$subject,$content,$active); - } + global $zbs, $wpdb, $ZBSCRM_t; - // ===== / Previously: last one hadn't got the html file, this ADDS file proper :) - - - // ===== Previously: adds template for 'invoice summary statement sent' - - #} default is admin email and CRM name - //now all done via zeroBSCRM_mailDelivery_defaultFromname - $from_name = zeroBSCRM_mailDelivery_defaultFromname(); - - /* This wasn't used in end, switched to default mail delivery opt - $from_address = zeroBSCRM_mailDelivery_defaultEmail();; //default WordPress admin email ? - $reply_to = ''; - $cc = ''; */ - $deliveryMethod = zeroBSCRM_getMailDeliveryDefault(); - - $ID = 7; - $reply_to = ''; - $cc = ''; - $bcc = ''; - - #} The email stuff... - $subject = __("Your Statement", 'zero-bs-crm'); - $content = zeroBSCRM_mail_retrieveDefaultBodyTemplate('invoicestatementsent'); - - // BRUTAL DELETE old one - $wpdb->delete( $ZBSCRM_t['system_mail_templates'], array( 'zbsmail_id' => $ID ) ); - - $active = 1; //1 = true.. - if(zeroBSCRM_mailTemplate_exists($ID) == 0){ - $content = zeroBSCRM_mailTemplate_processEmailHTML($content); - //zeroBSCRM_insertEmailTemplate($ID,$from_name,$from_address,$reply_to,$cc,$bcc,$subject,$content,$active); - zeroBSCRM_insertEmailTemplate($ID,$deliveryMethod,$bcc,$subject,$content,$active); - } + #} Check + create + zeroBSCRM_checkTablesExist(); - // ===== / Previously: adds template for 'invoice summary statement sent' + #} Make the DB emails... + zeroBSCRM_populateEmailTemplateList(); + // ===== Previously: Migration 2.96.3 - adds new template for 'client portal pw reset' - // ===== Previously: 2.97.4 - fixes duplicated email templates (found on 2 installs so far) + #} default is admin email and CRM name + // now all done via zeroBSCRM_mailDelivery_defaultFromname + $from_name = zeroBSCRM_mailDelivery_defaultFromname(); - // 7 template emails up to here :) - for ($i = 0; $i <= 7; $i++){ + /* + This wasn't used in end, switched to default mail delivery opt + $from_address = zeroBSCRM_mailDelivery_defaultEmail();; //default WordPress admin email ? + $reply_to = ''; + $cc = ''; */ + $deliveryMethod = zeroBSCRM_getMailDeliveryDefault(); + + $ID = 6; + $reply_to = ''; + $cc = ''; + $bcc = ''; + + #} The email stuff... + $subject = __( 'Your Client Portal Password', 'zero-bs-crm' ); + $content = zeroBSCRM_mail_retrieveDefaultBodyTemplate( 'clientportalpwreset' ); + $active = 1; // 1 = true.. + if ( zeroBSCRM_mailTemplate_exists( $ID ) == 0 ) { + $content = zeroBSCRM_mailTemplate_processEmailHTML( $content ); + // zeroBSCRM_insertEmailTemplate($ID,$from_name,$from_address,$reply_to,$cc,$bcc,$subject,$content,$active); + zeroBSCRM_insertEmailTemplate( $ID, $deliveryMethod, $bcc, $subject, $content, $active ); + } - // count em - $sql = $wpdb->prepare("SELECT ID FROM " . $ZBSCRM_t['system_mail_templates'] . " WHERE zbsmail_id = %d GROUP BY ID ORDER BY zbsmail_id DESC, zbsmail_lastupdated DESC", $i); - $r = $wpdb->get_results($sql, ARRAY_A); + // ===== / Previously: Migration 2.96.3 - // if too many, delete oldest (few?) - if (is_array($r) && count($r) > 1){ + // ===== Previously: last one hadn't got the html file, this ADDS file proper :) - $count = 0; + #} default is admin email and CRM name + // now all done via zeroBSCRM_mailDelivery_defaultFromname + $from_name = zeroBSCRM_mailDelivery_defaultFromname(); - // first stays, as the above selects in order by last updated - foreach ($r as $x){ + /* + This wasn't used in end, switched to default mail delivery opt + $from_address = zeroBSCRM_mailDelivery_defaultEmail();; //default WordPress admin email ? + $reply_to = ''; + $cc = ''; */ + $deliveryMethod = zeroBSCRM_getMailDeliveryDefault(); + + $ID = 6; + $reply_to = ''; + $cc = ''; + $bcc = ''; + + // BRUTAL DELETE old one + $wpdb->delete( $ZBSCRM_t['system_mail_templates'], array( 'zbsmail_id' => $ID ) ); + + #} The email stuff... + $subject = __( 'Your Client Portal Password', 'zero-bs-crm' ); + $content = zeroBSCRM_mail_retrieveDefaultBodyTemplate( 'clientportalpwreset' ); + + $active = 1; // 1 = true.. + if ( zeroBSCRM_mailTemplate_exists( $ID ) == 0 ) { + $content = zeroBSCRM_mailTemplate_processEmailHTML( $content ); + // zeroBSCRM_insertEmailTemplate($ID,$from_name,$from_address,$reply_to,$cc,$bcc,$subject,$content,$active); + zeroBSCRM_insertEmailTemplate( $ID, $deliveryMethod, $bcc, $subject, $content, $active ); + } - // if already got one, delete this (extra) - if ($count > 0){ + // ===== / Previously: last one hadn't got the html file, this ADDS file proper :) - // BRUTAL DELETE old one - $wpdb->delete( $ZBSCRM_t['system_mail_templates'], array( 'ID' => $x['ID'] ) ); + // ===== Previously: adds template for 'invoice summary statement sent' - } + #} default is admin email and CRM name + // now all done via zeroBSCRM_mailDelivery_defaultFromname + $from_name = zeroBSCRM_mailDelivery_defaultFromname(); - $count++; + /* + This wasn't used in end, switched to default mail delivery opt + $from_address = zeroBSCRM_mailDelivery_defaultEmail();; //default WordPress admin email ? + $reply_to = ''; + $cc = ''; */ + $deliveryMethod = zeroBSCRM_getMailDeliveryDefault(); + + $ID = 7; + $reply_to = ''; + $cc = ''; + $bcc = ''; + + #} The email stuff... + $subject = __( 'Your Statement', 'zero-bs-crm' ); + $content = zeroBSCRM_mail_retrieveDefaultBodyTemplate( 'invoicestatementsent' ); + + // BRUTAL DELETE old one + $wpdb->delete( $ZBSCRM_t['system_mail_templates'], array( 'zbsmail_id' => $ID ) ); + + $active = 1; // 1 = true.. + if ( zeroBSCRM_mailTemplate_exists( $ID ) == 0 ) { + $content = zeroBSCRM_mailTemplate_processEmailHTML( $content ); + // zeroBSCRM_insertEmailTemplate($ID,$from_name,$from_address,$reply_to,$cc,$bcc,$subject,$content,$active); + zeroBSCRM_insertEmailTemplate( $ID, $deliveryMethod, $bcc, $subject, $content, $active ); + } - } + // ===== / Previously: adds template for 'invoice summary statement sent' + + // ===== Previously: 2.97.4 - fixes duplicated email templates (found on 2 installs so far) + + // 7 template emails up to here :) + for ( $i = 0; $i <= 7; $i++ ) { + + // count em + $sql = $wpdb->prepare( 'SELECT ID FROM ' . $ZBSCRM_t['system_mail_templates'] . ' WHERE zbsmail_id = %d GROUP BY ID ORDER BY zbsmail_id DESC, zbsmail_lastupdated DESC', $i ); + $r = $wpdb->get_results( $sql, ARRAY_A ); + + // if too many, delete oldest (few?) + if ( is_array( $r ) && count( $r ) > 1 ) { + + $count = 0; + + // first stays, as the above selects in order by last updated + foreach ( $r as $x ) { + + // if already got one, delete this (extra) + if ( $count > 0 ) { + + // BRUTAL DELETE old one + $wpdb->delete( $ZBSCRM_t['system_mail_templates'], array( 'ID' => $x['ID'] ) ); } + ++$count; + + } } - - // ===== / Previously: 2.97.4 - fixes duplicated email templates (found on 2 installs so far) - + } + + // ===== / Previously: 2.97.4 - fixes duplicated email templates (found on 2 installs so far) - // ===== Previously: 4.0.7 - corrects outdated task notification template + // ===== Previously: 4.0.7 - corrects outdated task notification template - // retrieve existing template - hardtyped - $existingTemplate = $wpdb->get_var('SELECT zbsmail_body FROM '.$ZBSCRM_t['system_mail_templates'].' WHERE ID = 6'); + // retrieve existing template - hardtyped + $existingTemplate = $wpdb->get_var( 'SELECT zbsmail_body FROM ' . $ZBSCRM_t['system_mail_templates'] . ' WHERE ID = 6' ); - // load new - $newTemplate = zeroBSCRM_mail_retrieveDefaultBodyTemplate( 'tasknotification' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + // load new + $newTemplate = zeroBSCRM_mail_retrieveDefaultBodyTemplate( 'tasknotification' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase // back it up into a WP option if was different if ( $existingTemplate !== $newTemplate ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase update_option( 'jpcrm_tasknotificationtemplate', $existingTemplate, false ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase } - // overwrite - $sql = "UPDATE " . $ZBSCRM_t['system_mail_templates'] . " SET zbsmail_body = %s WHERE ID = 6"; - $q = $wpdb->prepare($sql,array($newTemplate)); - $wpdb->query($q); - - // ===== / Previously: 4.0.7 - corrects outdated task notification template - - - // ===== Previously: 4.0.8 - Set the default reference type for invoices & Update the existing template for email notifications (had old label) - - if ( $zbs->DAL->invoices->getFullCount() > 0 ) { - // The user has used the invoice module. Default reference type = manual - $zbs->settings->update( 'reftype', 'manual' ); - } + // overwrite + $sql = 'UPDATE ' . $ZBSCRM_t['system_mail_templates'] . ' SET zbsmail_body = %s WHERE ID = 6'; + $q = $wpdb->prepare( $sql, array( $newTemplate ) ); + $wpdb->query( $q ); + // ===== / Previously: 4.0.7 - corrects outdated task notification template - // Update the existing template for email notifications (had old label) - global $ZBSCRM_t,$wpdb; + // ===== Previously: 4.0.8 - Set the default reference type for invoices & Update the existing template for email notifications (had old label) - // retrieve existing template - hardtyped - $existingTemplate = $wpdb->get_var('SELECT zbsmail_body FROM '.$ZBSCRM_t['system_mail_templates'].' WHERE ID = 4'); + if ( $zbs->DAL->invoices->getFullCount() > 0 ) { + // The user has used the invoice module. Default reference type = manual + $zbs->settings->update( 'reftype', 'manual' ); + } - // load new - $newTemplate = zeroBSCRM_mail_retrieveDefaultBodyTemplate('invoicesent'); + // Update the existing template for email notifications (had old label) + global $ZBSCRM_t, $wpdb; - // back it up into a WP option if was different - if ($existingTemplate !== $newTemplate) update_option('jpcrm_invnotificationtemplate',$existingTemplate, false); + // retrieve existing template - hardtyped + $existingTemplate = $wpdb->get_var( 'SELECT zbsmail_body FROM ' . $ZBSCRM_t['system_mail_templates'] . ' WHERE ID = 4' ); - // overwrite - $sql = "UPDATE " . $ZBSCRM_t['system_mail_templates'] . " SET zbsmail_body = %s WHERE ID = 4"; - $q = $wpdb->prepare($sql,array($newTemplate)); - $wpdb->query($q); + // load new + $newTemplate = zeroBSCRM_mail_retrieveDefaultBodyTemplate( 'invoicesent' ); - // ===== / Previously: 4.0.8 - Set the default reference type for invoices & Update the existing template for email notifications (had old label) + // back it up into a WP option if was different + if ( $existingTemplate !== $newTemplate ) { + update_option( 'jpcrm_invnotificationtemplate', $existingTemplate, false ); + } - zeroBSCRM_migrations_markComplete('2963',array('updated'=>'1')); + // overwrite + $sql = 'UPDATE ' . $ZBSCRM_t['system_mail_templates'] . ' SET zbsmail_body = %s WHERE ID = 4'; + $q = $wpdb->prepare( $sql, array( $newTemplate ) ); + $wpdb->query( $q ); - } + // ===== / Previously: 4.0.8 - Set the default reference type for invoices & Update the existing template for email notifications (had old label) + zeroBSCRM_migrations_markComplete( '2963', array( 'updated' => '1' ) ); +} /* * Migration 2.99.99 - set permalinks to flush (was used with v3.0 migration, left in tact as portal may be dependent) */ - function zeroBSCRM_migration_29999(){ - - // set permalinks to flush, this'll cause them to be refreshed on 3000 migration - // ... as that has preload setting - jpcrm_flag_for_flush_rewrite(); +function zeroBSCRM_migration_29999() { - // fini - zeroBSCRM_migrations_markComplete('29999',array('updated'=>1)); + // set permalinks to flush, this'll cause them to be refreshed on 3000 migration + // ... as that has preload setting + jpcrm_flag_for_flush_rewrite(); - } + // fini + zeroBSCRM_migrations_markComplete( '29999', array( 'updated' => 1 ) ); +} /* * Migration 4.11.0 - secure upload folders - * previously: - * 4.5.0 - Adds indexing protection to directories with potentially sensitive .html files + * previously: + * 4.5.0 - Adds indexing protection to directories with potentially sensitive .html files * 4.11.0 - secure upload folders */ - function zeroBSCRM_migration_411(){ - - $wp_uploads_dir = wp_upload_dir(); +function zeroBSCRM_migration_411() { - // directories to secure - // if these ever expand beyond this we should move the list to core & manage periodic checks - $directories = array( + $wp_uploads_dir = wp_upload_dir(); - ZEROBSCRM_PATH . 'templates/', - ZEROBSCRM_PATH . 'templates/emails/', - ZEROBSCRM_PATH . 'templates/invoices/', - ZEROBSCRM_PATH . 'templates/quotes/', + // directories to secure + // if these ever expand beyond this we should move the list to core & manage periodic checks + $directories = array( - $wp_uploads_dir['basedir'] . '/' . 'zbscrm-store/_wip/', + ZEROBSCRM_PATH . 'templates/', + ZEROBSCRM_PATH . 'templates/emails/', + ZEROBSCRM_PATH . 'templates/invoices/', + ZEROBSCRM_PATH . 'templates/quotes/', - ); + $wp_uploads_dir['basedir'] . '/' . 'zbscrm-store/_wip/', - // secure them! - foreach ( $directories as $directory ){ - jpcrm_create_and_secure_dir_from_external_access( $directory, true ); - } + ); - jpcrm_create_and_secure_dir_from_external_access( $wp_uploads_dir['basedir'] . '/' . 'zbscrm-store/', false ); + // secure them! + foreach ( $directories as $directory ) { + jpcrm_create_and_secure_dir_from_external_access( $directory, true ); + } - // mark complete - zeroBSCRM_migrations_markComplete('411',array('updated'=>1)); + jpcrm_create_and_secure_dir_from_external_access( $wp_uploads_dir['basedir'] . '/' . 'zbscrm-store/', false ); - } + // mark complete + zeroBSCRM_migrations_markComplete( '411', array( 'updated' => 1 ) ); +} /* * Migration 5.0 - Alter external sources table for existing users (added origin) */ - function zeroBSCRM_migration_50(){ +function zeroBSCRM_migration_50() { - global $zbs, $wpdb, $ZBSCRM_t; + global $zbs, $wpdb, $ZBSCRM_t; - // external source tweak - if ( !zeroBSCRM_migration_tableHasColumn( $ZBSCRM_t['externalsources'], 'zbss_origin' ) ){ + // external source tweak + if ( ! zeroBSCRM_migration_tableHasColumn( $ZBSCRM_t['externalsources'], 'zbss_origin' ) ) { - $sql = "ALTER TABLE " . $ZBSCRM_t['externalsources'] . " ADD COLUMN `zbss_origin` VARCHAR(400) NULL DEFAULT NULL AFTER `zbss_uid`, ADD INDEX (zbss_origin);"; - $wpdb->query( $sql ); + $sql = 'ALTER TABLE ' . $ZBSCRM_t['externalsources'] . ' ADD COLUMN `zbss_origin` VARCHAR(400) NULL DEFAULT NULL AFTER `zbss_uid`, ADD INDEX (zbss_origin);'; + $wpdb->query( $sql ); - } - - // add transaction status - - // build string - $transaction_statuses = zeroBSCRM_getTransactionsStatuses(true); - $deleted_string = __( 'Deleted', 'zero-bs-crm' ); - if ( !in_array( $deleted_string, $transaction_statuses ) ){ - $transaction_statuses[] = $deleted_string; - } - $transaction_statuses_str = implode( ',', $transaction_statuses ); - - // update - $customisedFields = $zbs->settings->get('customisedfields'); - $customisedFields['transactions']['status'][1] = $transaction_statuses_str; - $zbs->settings->update('customisedfields',$customisedFields); + } + // add transaction status - // mark complete - zeroBSCRM_migrations_markComplete( '50', array( 'updated' => 1 ) ); - + // build string + $transaction_statuses = zeroBSCRM_getTransactionsStatuses( true ); + $deleted_string = __( 'Deleted', 'zero-bs-crm' ); + if ( ! in_array( $deleted_string, $transaction_statuses ) ) { + $transaction_statuses[] = $deleted_string; } + $transaction_statuses_str = implode( ',', $transaction_statuses ); + + // update + $customisedFields = $zbs->settings->get( 'customisedfields' ); + $customisedFields['transactions']['status'][1] = $transaction_statuses_str; + $zbs->settings->update( 'customisedfields', $customisedFields ); + // mark complete + zeroBSCRM_migrations_markComplete( '50', array( 'updated' => 1 ) ); +} /* * 5.3 - Migrate all encrypted data to new encryption endpoints */ - function zeroBSCRM_migration_53(){ +function zeroBSCRM_migration_53() { - global $zbs; + global $zbs; - // load libs + // load libs - // ~5.3 - if ( ! function_exists( 'zeroBSCRM_encrypt' ) ) { - require( ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Encryption.php' ); - } + // ~5.3 + if ( ! function_exists( 'zeroBSCRM_encrypt' ) ) { + require ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Encryption.php'; + } - // 5.3~ - $zbs->load_encryption(); + // 5.3~ + $zbs->load_encryption(); - // count - $successful_recryptions = 0; + // count + $successful_recryptions = 0; - // Mail Delivery methods (if any): + // Mail Delivery methods (if any): - // previous decrypt key - $decryption_key = hex2bin( zeroBSCRM_getSetting('smtpkey') ); + // previous decrypt key + $decryption_key = hex2bin( zeroBSCRM_getSetting( 'smtpkey' ) ); - // retrieve existing - $existing_mail_delivery_methods = zeroBSCRM_getSetting( 'smtpaccs' ); - if (!is_array($existing_mail_delivery_methods)) $existing_mail_delivery_methods = array(); + // retrieve existing + $existing_mail_delivery_methods = zeroBSCRM_getSetting( 'smtpaccs' ); + if ( ! is_array( $existing_mail_delivery_methods ) ) { + $existing_mail_delivery_methods = array(); + } - // cycle through them and re-encrypt - $replacement_delivery_methods = array(); - foreach ( $existing_mail_delivery_methods as $method_key => $method_array ){ + // cycle through them and re-encrypt + $replacement_delivery_methods = array(); + foreach ( $existing_mail_delivery_methods as $method_key => $method_array ) { - $updated_method_array = $method_array; + $updated_method_array = $method_array; - if ( isset( $method_array['pass'] ) ){ + if ( isset( $method_array['pass'] ) ) { - // decrypt (hiding deprecation notices via param) - $password = zeroBSCRM_encryption_unsafe_process( 'decrypt', $method_array['pass'], $decryption_key, zeroBSCRM_get_iv( true ), true ); + // decrypt (hiding deprecation notices via param) + $password = zeroBSCRM_encryption_unsafe_process( 'decrypt', $method_array['pass'], $decryption_key, zeroBSCRM_get_iv( true ), true ); - // This is used as a fallback because some users can still have passwords - // that were encrypted using the wrong IV. - if ( !$password ) { - $password = zeroBSCRM_encryption_unsafe_process( 'decrypt', $method_array['pass'], $decryption_key, $decryption_key, true ); - } + // This is used as a fallback because some users can still have passwords + // that were encrypted using the wrong IV. + if ( ! $password ) { + $password = zeroBSCRM_encryption_unsafe_process( 'decrypt', $method_array['pass'], $decryption_key, $decryption_key, true ); + } - if ( $password ) { + if ( $password ) { - // encrypt password: - $updated_method_array['pass'] = $zbs->encryption->encrypt( $password, 'smtp' ); + // encrypt password: + $updated_method_array['pass'] = $zbs->encryption->encrypt( $password, 'smtp' ); - } else { + } else { - // keep existing ciphertext; likely already updated but otherwise corrupt - $updated_method_array['pass'] = $method_array['pass']; + // keep existing ciphertext; likely already updated but otherwise corrupt + $updated_method_array['pass'] = $method_array['pass']; - } + } - $successful_recryptions++; + ++$successful_recryptions; - } + } - $replacement_delivery_methods[ $method_key ] = $updated_method_array; + $replacement_delivery_methods[ $method_key ] = $updated_method_array; - } + } - // update em - $zbs->settings->update( 'smtpaccs', $replacement_delivery_methods ); + // update em + $zbs->settings->update( 'smtpaccs', $replacement_delivery_methods ); - // There was some old usage of pwmanager on companys with CPTs, for now we're skipping support. - // $pws = get_post_meta($id,$zbsPasswordManager['dbkey'],true); + // There was some old usage of pwmanager on companys with CPTs, for now we're skipping support. + // $pws = get_post_meta($id,$zbsPasswordManager['dbkey'],true); // hash secret if not already hashed $api_secret = $zbs->DAL->setting( 'api_secret' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase @@ -655,233 +661,222 @@ function zeroBSCRM_migration_53(){ $zbs->DAL->updateSetting( 'api_secret', $hashed_api_secret ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase } - global $wpdb, $ZBSCRM_t; - // add indexes for performance - if ( jpcrm_database_server_has_ability('fulltext_index') && !jpcrm_migration_table_has_index( $ZBSCRM_t['customfields'], 'search' ) ) { - $sql = 'ALTER TABLE ' . $ZBSCRM_t['customfields'] . ' ADD FULLTEXT INDEX `search` (`zbscf_objval`);'; - $wpdb->query( $sql ); - } - if ( !jpcrm_migration_table_has_index( $ZBSCRM_t['taglinks'], 'zbstl_tagid+zbstl_objtype' ) ) { - $sql = 'ALTER TABLE ' . $ZBSCRM_t['taglinks'] . ' ADD INDEX `zbstl_tagid+zbstl_objtype` (`zbstl_tagid`,`zbstl_objtype`) USING BTREE;'; - $wpdb->query( $sql ); - } - if ( !jpcrm_migration_table_has_index( $ZBSCRM_t['externalsources'], 'zbss_uid+zbss_source+zbss_objtype' ) ) { - $sql = 'ALTER TABLE ' . $ZBSCRM_t['externalsources'] . ' ADD INDEX `zbss_uid+zbss_source+zbss_objtype` (`zbss_uid`,`zbss_source`,`zbss_objtype`) USING BTREE;'; - $wpdb->query( $sql ); - } - if ( !jpcrm_migration_table_has_index( $ZBSCRM_t['meta'], 'zbsm_objid+zbsm_key+zbsm_objtype' ) ) { - $sql = 'ALTER TABLE ' . $ZBSCRM_t['meta'] . ' ADD INDEX `zbsm_objid+zbsm_key+zbsm_objtype` (`zbsm_objid`,`zbsm_key`,`zbsm_objtype`) USING BTREE;'; - $wpdb->query( $sql ); - } - if ( !jpcrm_migration_table_has_index( $ZBSCRM_t['logs'], 'zbsl_created' ) ) { - $sql = 'ALTER TABLE ' . $ZBSCRM_t['logs'] . ' ADD INDEX `zbsl_created` (`zbsl_created`) USING BTREE;'; - $wpdb->query( $sql ); - } - if ( !jpcrm_migration_table_has_index( $ZBSCRM_t['contacts'], 'zbsc_status' ) ) { - $sql = 'ALTER TABLE ' . $ZBSCRM_t['contacts'] . ' ADD INDEX `zbsc_status` (`zbsc_status`) USING BTREE;'; - $wpdb->query( $sql ); - } - - // remove errant .htaccess file - $wp_uploads_dir = wp_upload_dir(); - $errant_htaccess = $wp_uploads_dir['basedir'] . '/' . 'zbscrm-store/.htaccess'; - if ( file_exists( $errant_htaccess ) ) { - unlink( $errant_htaccess ); - } - // mark complete - zeroBSCRM_migrations_markComplete( '53', array( 'updated' => $successful_recryptions ) ); + global $wpdb, $ZBSCRM_t; + // add indexes for performance + if ( jpcrm_database_server_has_ability( 'fulltext_index' ) && ! jpcrm_migration_table_has_index( $ZBSCRM_t['customfields'], 'search' ) ) { + $sql = 'ALTER TABLE ' . $ZBSCRM_t['customfields'] . ' ADD FULLTEXT INDEX `search` (`zbscf_objval`);'; + $wpdb->query( $sql ); + } + if ( ! jpcrm_migration_table_has_index( $ZBSCRM_t['taglinks'], 'zbstl_tagid+zbstl_objtype' ) ) { + $sql = 'ALTER TABLE ' . $ZBSCRM_t['taglinks'] . ' ADD INDEX `zbstl_tagid+zbstl_objtype` (`zbstl_tagid`,`zbstl_objtype`) USING BTREE;'; + $wpdb->query( $sql ); + } + if ( ! jpcrm_migration_table_has_index( $ZBSCRM_t['externalsources'], 'zbss_uid+zbss_source+zbss_objtype' ) ) { + $sql = 'ALTER TABLE ' . $ZBSCRM_t['externalsources'] . ' ADD INDEX `zbss_uid+zbss_source+zbss_objtype` (`zbss_uid`,`zbss_source`,`zbss_objtype`) USING BTREE;'; + $wpdb->query( $sql ); + } + if ( ! jpcrm_migration_table_has_index( $ZBSCRM_t['meta'], 'zbsm_objid+zbsm_key+zbsm_objtype' ) ) { + $sql = 'ALTER TABLE ' . $ZBSCRM_t['meta'] . ' ADD INDEX `zbsm_objid+zbsm_key+zbsm_objtype` (`zbsm_objid`,`zbsm_key`,`zbsm_objtype`) USING BTREE;'; + $wpdb->query( $sql ); + } + if ( ! jpcrm_migration_table_has_index( $ZBSCRM_t['logs'], 'zbsl_created' ) ) { + $sql = 'ALTER TABLE ' . $ZBSCRM_t['logs'] . ' ADD INDEX `zbsl_created` (`zbsl_created`) USING BTREE;'; + $wpdb->query( $sql ); + } + if ( ! jpcrm_migration_table_has_index( $ZBSCRM_t['contacts'], 'zbsc_status' ) ) { + $sql = 'ALTER TABLE ' . $ZBSCRM_t['contacts'] . ' ADD INDEX `zbsc_status` (`zbsc_status`) USING BTREE;'; + $wpdb->query( $sql ); + } + // remove errant .htaccess file + $wp_uploads_dir = wp_upload_dir(); + $errant_htaccess = $wp_uploads_dir['basedir'] . '/' . 'zbscrm-store/.htaccess'; + if ( file_exists( $errant_htaccess ) ) { + unlink( $errant_htaccess ); } + // mark complete + zeroBSCRM_migrations_markComplete( '53', array( 'updated' => $successful_recryptions ) ); +} /* * Migration 5.4 - * - Support pinned logs. - * - Migrate all log meta stored in old dehydrated fashion. (Will do in 1k chunks until finished.) + * - Support pinned logs. + * - Migrate all log meta stored in old dehydrated fashion. (Will do in 1k chunks until finished.) */ - function zeroBSCRM_migration_54(){ - - global $zbs, $wpdb, $ZBSCRM_t; +function zeroBSCRM_migration_54() { - // add zbsl_pinned to log table if not existing - if ( !zeroBSCRM_migration_tableHasColumn( $ZBSCRM_t['logs'], 'zbsl_pinned' ) ) { - $sql = 'ALTER TABLE ' . $ZBSCRM_t['logs'] . ' ADD `zbsl_pinned` int(1) NULL AFTER `zbsl_longdesc`;'; - $wpdb->query( $sql ); - } + global $zbs, $wpdb, $ZBSCRM_t; - // get outdated log meta count - $outdated_log_meta_count = (int)$wpdb->get_var( 'SELECT COUNT(ID) FROM ' . $ZBSCRM_t['meta'] . ' WHERE zbsm_objtype = 8 AND zbsm_key = "logmeta"' ); + // add zbsl_pinned to log table if not existing + if ( ! zeroBSCRM_migration_tableHasColumn( $ZBSCRM_t['logs'], 'zbsl_pinned' ) ) { + $sql = 'ALTER TABLE ' . $ZBSCRM_t['logs'] . ' ADD `zbsl_pinned` int(1) NULL AFTER `zbsl_longdesc`;'; + $wpdb->query( $sql ); + } - if ( $outdated_log_meta_count > 0 ) { + // get outdated log meta count + $outdated_log_meta_count = (int) $wpdb->get_var( 'SELECT COUNT(ID) FROM ' . $ZBSCRM_t['meta'] . ' WHERE zbsm_objtype = 8 AND zbsm_key = "logmeta"' ); - // get outdated meta records - $outdated_log_meta_records = $wpdb->get_results( 'SELECT * FROM ' . $ZBSCRM_t['meta'] . ' WHERE zbsm_objtype = 8 AND zbsm_key = "logmeta" ORDER BY ID DESC LIMIT 5000' ); + if ( $outdated_log_meta_count > 0 ) { - foreach ( $outdated_log_meta_records as $log_record ){ + // get outdated meta records + $outdated_log_meta_records = $wpdb->get_results( 'SELECT * FROM ' . $ZBSCRM_t['meta'] . ' WHERE zbsm_objtype = 8 AND zbsm_key = "logmeta" ORDER BY ID DESC LIMIT 5000' ); - // hydrate - Note that `[]` doesn't hydrate into array with this - $log_meta = $zbs->DAL->decodeIfJSON( $zbs->DAL->stripSlashes( $log_record->zbsm_val ) ); + foreach ( $outdated_log_meta_records as $log_record ) { - // insert new line foreach meta - if ( is_array( $log_meta ) ){ + // hydrate - Note that `[]` doesn't hydrate into array with this + $log_meta = $zbs->DAL->decodeIfJSON( $zbs->DAL->stripSlashes( $log_record->zbsm_val ) ); - foreach ( $log_meta as $key => $value ){ + // insert new line foreach meta + if ( is_array( $log_meta ) ) { - $zbs->DAL->updateMeta( ZBS_TYPE_LOG, $log_record->zbsm_objid, $zbs->DAL->makeSlug( $key ), $value ); + foreach ( $log_meta as $key => $value ) { - } + $zbs->DAL->updateMeta( ZBS_TYPE_LOG, $log_record->zbsm_objid, $zbs->DAL->makeSlug( $key ), $value ); } - - // delete old 'dehydrated whole' line - zeroBSCRM_db2_deleteGeneric( $log_record->ID, 'meta' ); - } - // any left? - $outdated_log_meta_count = (int)$wpdb->get_var( 'SELECT COUNT(ID) FROM ' . $ZBSCRM_t['meta'] . ' WHERE zbsm_objtype = 8 AND zbsm_key = "logmeta"' ); + // delete old 'dehydrated whole' line + zeroBSCRM_db2_deleteGeneric( $log_record->ID, 'meta' ); } - if ( $outdated_log_meta_count == 0 ){ + // any left? + $outdated_log_meta_count = (int) $wpdb->get_var( 'SELECT COUNT(ID) FROM ' . $ZBSCRM_t['meta'] . ' WHERE zbsm_objtype = 8 AND zbsm_key = "logmeta"' ); - // mark complete - zeroBSCRM_migrations_markComplete( '54', array( 'updated' => 1 ) ); + } - } + if ( $outdated_log_meta_count == 0 ) { + + // mark complete + zeroBSCRM_migrations_markComplete( '54', array( 'updated' => 1 ) ); } +} /* * Migration 5.4.3 * - Removes unwanted .htaccess files */ - function zeroBSCRM_migration_543() { - // recursively deletes all .htaccess files starting from the root storage folder - $root_storage = zeroBSCRM_privatisedDirCheck(); - if ( $root_storage !== false ) { - $recursive_file_iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $root_storage['path'] ) ); - $htaccess_files = array(); - - foreach ( $recursive_file_iterator as $file ) { - if ( $file->isDir() || $file->getBasename() != '.htaccess' ) { - continue; - } - $htaccess_files[] = $file->getPathname(); +function zeroBSCRM_migration_543() { + // recursively deletes all .htaccess files starting from the root storage folder + $root_storage = zeroBSCRM_privatisedDirCheck(); + if ( $root_storage !== false ) { + $recursive_file_iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $root_storage['path'] ) ); + $htaccess_files = array(); + + foreach ( $recursive_file_iterator as $file ) { + if ( $file->isDir() || $file->getBasename() != '.htaccess' ) { + continue; } + $htaccess_files[] = $file->getPathname(); + } - foreach ( $htaccess_files as $errant_htaccess ) { - if ( is_file( $errant_htaccess ) ){ - unlink( $errant_htaccess ); - } + foreach ( $htaccess_files as $errant_htaccess ) { + if ( is_file( $errant_htaccess ) ) { + unlink( $errant_htaccess ); } } - - // mark this migration as complete - zeroBSCRM_migrations_markComplete( '543', array( 'updated' => 1 ) ); } + // mark this migration as complete + zeroBSCRM_migrations_markComplete( '543', array( 'updated' => 1 ) ); +} + /* * Migration 5.4.4 * - Forces re-install of default fonts (moved to new JPCRM storage folder) */ - function zeroBSCRM_migration_544(){ +function zeroBSCRM_migration_544() { - global $zbs; - - // font reinstall - $shouldBeInstalled = zeroBSCRM_getSetting( 'feat_pdfinv' ); - if ( $shouldBeInstalled == "1" ){ + global $zbs; - // force reinstall of fonts - $fonts = $zbs->get_fonts(); - if ( !$fonts->extract_and_install_default_fonts() ) { - return false; - } + // font reinstall + $shouldBeInstalled = zeroBSCRM_getSetting( 'feat_pdfinv' ); + if ( $shouldBeInstalled == '1' ) { + // force reinstall of fonts + $fonts = $zbs->get_fonts(); + if ( ! $fonts->extract_and_install_default_fonts() ) { + return false; } - - // mark complete - zeroBSCRM_migrations_markComplete( '544', array( 'updated' => 1 ) ); - } + // mark complete + zeroBSCRM_migrations_markComplete( '544', array( 'updated' => 1 ) ); +} + /* * Migration 5.5 * - Deletes orphaned rows linked to invoices in the objlinks table */ - function zeroBSCRM_migration_55() { +function zeroBSCRM_migration_55() { - global $zbs, $wpdb, $ZBSCRM_t; + global $zbs, $wpdb, $ZBSCRM_t; - // Deletes links when missing invoices are the 'to' object - $wpdb->query( - ' DELETE FROM ' . $ZBSCRM_t['objlinks'] - . ' WHERE ' - . ' zbsol_objtype_to = ' . ZBS_TYPE_INVOICE - . ' AND zbsol_objid_to NOT IN ( SELECT ID from ' . $ZBSCRM_t['invoices'] . ' ) ' - ); - - // Deletes links when missing invoices are the 'from' object - $wpdb->query( - ' DELETE FROM ' . $ZBSCRM_t['objlinks'] - . ' WHERE ' - . ' zbsol_objtype_from = ' . ZBS_TYPE_INVOICE - . ' AND zbsol_objid_from NOT IN ( SELECT ID from ' . $ZBSCRM_t['invoices'] . ' ) ' - ); + // Deletes links when missing invoices are the 'to' object + $wpdb->query( + ' DELETE FROM ' . $ZBSCRM_t['objlinks'] + . ' WHERE ' + . ' zbsol_objtype_to = ' . ZBS_TYPE_INVOICE + . ' AND zbsol_objid_to NOT IN ( SELECT ID from ' . $ZBSCRM_t['invoices'] . ' ) ' + ); - // Deletes orphaned line items - $wpdb->query( - ' DELETE FROM ' . $ZBSCRM_t['lineitems'] . ' WHERE ID NOT IN' - . ' (' - . ' SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] - . ' WHERE ' - . ' zbsol_objtype_from = ' . ZBS_TYPE_LINEITEM - . ' )' - ); + // Deletes links when missing invoices are the 'from' object + $wpdb->query( + ' DELETE FROM ' . $ZBSCRM_t['objlinks'] + . ' WHERE ' + . ' zbsol_objtype_from = ' . ZBS_TYPE_INVOICE + . ' AND zbsol_objid_from NOT IN ( SELECT ID from ' . $ZBSCRM_t['invoices'] . ' ) ' + ); - // mark complete - zeroBSCRM_migrations_markComplete( '55', array( 'updated' => 1 ) ); + // Deletes orphaned line items + $wpdb->query( + ' DELETE FROM ' . $ZBSCRM_t['lineitems'] . ' WHERE ID NOT IN' + . ' (' + . ' SELECT zbsol_objid_from FROM ' . $ZBSCRM_t['objlinks'] + . ' WHERE ' + . ' zbsol_objtype_from = ' . ZBS_TYPE_LINEITEM + . ' )' + ); - } + // mark complete + zeroBSCRM_migrations_markComplete( '55', array( 'updated' => 1 ) ); +} /* * Migration 5.5a * Recompiles segments, runs on later schedule (wp_loaded) */ - function zeroBSCRM_migration_55a(){ +function zeroBSCRM_migration_55a() { - global $zbs; - - // recompile segments with new condition names - $zbs->DAL->segments->compile_all_segments(); - - // mark complete - zeroBSCRM_migrations_markComplete( '55a', array( 'updated' => 1 ) ); - - - } + global $zbs; + // recompile segments with new condition names + $zbs->DAL->segments->compile_all_segments(); + // mark complete + zeroBSCRM_migrations_markComplete( '55a', array( 'updated' => 1 ) ); +} /* * Migration 5.5.1 * - Deletes orphaned aka rows linked to contacts since deleted */ - function zeroBSCRM_migration_551() { - - global $zbs, $wpdb, $ZBSCRM_t; +function zeroBSCRM_migration_551() { - // Deletes orphaned aka rows - $wpdb->query( - 'DELETE FROM ' . $ZBSCRM_t['aka'] - . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_id NOT IN' - . ' (SELECT id FROM ' . $ZBSCRM_t['contacts'] . ')' - ); + global $zbs, $wpdb, $ZBSCRM_t; - // mark complete - zeroBSCRM_migrations_markComplete( '551', array( 'updated' => 1 ) ); + // Deletes orphaned aka rows + $wpdb->query( + 'DELETE FROM ' . $ZBSCRM_t['aka'] + . ' WHERE aka_type = ' . ZBS_TYPE_CONTACT . ' AND aka_id NOT IN' + . ' (SELECT id FROM ' . $ZBSCRM_t['contacts'] . ')' + ); - } + // mark complete + zeroBSCRM_migrations_markComplete( '551', array( 'updated' => 1 ) ); +} /** * Migration 5.6.0 @@ -1353,98 +1348,101 @@ function zeroBSCRM_migration_ensure_notifications_table() { return true; } -/* ====================================================== +/* +====================================================== / MIGRATIONS - ====================================================== */ - + ====================================================== */ -/* ====================================================== - MIGRATION Helpers - ====================================================== */ +/* +====================================================== + MIGRATION Helpers + ====================================================== */ - // simplistic arr manager - function zeroBSCRM_migration_addErrToStack($err=array(),$errKey=''){ + // simplistic arr manager +function zeroBSCRM_migration_addErrToStack( $err = array(), $errKey = '' ) { - if ($errKey !== ''){ + if ( $errKey !== '' ) { - $existing = get_option($errKey, array()); + $existing = get_option( $errKey, array() ); - // catch err in err stack. - if (!is_array($existing)) $existing = array(); + // catch err in err stack. + if ( ! is_array( $existing ) ) { + $existing = array(); + } - // add + update - $existing[] = $err; - update_option( $errKey, $existing, false); + // add + update + $existing[] = $err; + update_option( $errKey, $existing, false ); return true; - } + } - return false; - } + return false; +} - // checks if a column already exists - // note $tableName is used unchecked - function zeroBSCRM_migration_tableHasColumn( $table_name, $column_name ){ + // checks if a column already exists + // note $tableName is used unchecked +function zeroBSCRM_migration_tableHasColumn( $table_name, $column_name ) { - global $wpdb; + global $wpdb; - if ( !empty( $table_name ) && !empty( $column_name ) ){ + if ( ! empty( $table_name ) && ! empty( $column_name ) ) { - $query = $wpdb->prepare( "SHOW COLUMNS FROM " . $table_name . " LIKE %s", $column_name ); - - $row = $wpdb->get_results( $query ); - - if ( is_array( $row ) && count( $row ) > 0 ){ + $query = $wpdb->prepare( 'SHOW COLUMNS FROM ' . $table_name . ' LIKE %s', $column_name ); - return true; + $row = $wpdb->get_results( $query ); - } + if ( is_array( $row ) && count( $row ) > 0 ) { - } + return true; - return false; + } + } - } + return false; +} - /* - * Verifies if a mysql table has an index named X - */ - function jpcrm_migration_table_has_index( $table_name, $index_name ){ + /* + * Verifies if a mysql table has an index named X + */ +function jpcrm_migration_table_has_index( $table_name, $index_name ) { - global $wpdb; + global $wpdb; - $query = $wpdb->prepare( "SHOW INDEX FROM " . $table_name . " WHERE Key_name = %s", $index_name ); - $row = $wpdb->get_results( $query ); + $query = $wpdb->prepare( 'SHOW INDEX FROM ' . $table_name . ' WHERE Key_name = %s', $index_name ); + $row = $wpdb->get_results( $query ); - if ( is_array( $row ) && count( $row ) > 0){ + if ( is_array( $row ) && count( $row ) > 0 ) { return true; - } + } - return false; - - } - - /** - * Retrieves the data typo of the given colemn name in the given table name. - * It's worth noting that it will have the size of the field too, so `int(10)` - * rather than just `int`. - * - * @param $table_name string The table name to query. - * @param $column_name string The column name to query. - * - * @return string|false The column type as a string, or `false` on failure. - */ - function zeraBSCRM_migration_get_column_data_type( $table_name, $column_name ) { - global $wpdb; + return false; +} + + /** + * Retrieves the data typo of the given colemn name in the given table name. + * It's worth noting that it will have the size of the field too, so `int(10)` + * rather than just `int`. + * + * @param $table_name string The table name to query. + * @param $column_name string The column name to query. + * + * @return string|false The column type as a string, or `false` on failure. + */ +function zeraBSCRM_migration_get_column_data_type( $table_name, $column_name ) { + global $wpdb; - $column = $wpdb->get_row( $wpdb->prepare( - "SHOW COLUMNS FROM $table_name LIKE %s", - $column_name ) ); - return empty( $column ) ? false : $column->Type; - } + $column = $wpdb->get_row( + $wpdb->prepare( + "SHOW COLUMNS FROM $table_name LIKE %s", + $column_name + ) + ); + return empty( $column ) ? false : $column->Type; +} /** * Loads everything needed to use the WP_Filesystem_Direct class. @@ -1519,6 +1517,7 @@ function jpcrm_migration_regenerate_tag_slugs_for_obj_type( int $obj_type_id ) { } } -/* ====================================================== - / MIGRATION Helpers - ====================================================== */ +/* +====================================================== + / MIGRATION Helpers + ====================================================== */ diff --git a/projects/plugins/crm/includes/ZeroBSCRM.NotifyMe.php b/projects/plugins/crm/includes/ZeroBSCRM.NotifyMe.php index 15ee392b4403..c1adbf4dcc33 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.NotifyMe.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.NotifyMe.php @@ -1,5 +1,5 @@ -slugs['notifications']); - echo ""; + // jQuery fills in the number in the bubble.. + if ( is_user_logged_in() && zeroBSCRM_permsNotify() ) { + $url = zeroBSCRM_getAdminURL( $zbs->slugs['notifications'] ); + echo ""; - } + } } #} this is the action to add the notification icon to the new admin top menu -add_action('zbs-crm-notify','zeroBSCRM_notify_me'); +add_action( 'zbs-crm-notify', 'zeroBSCRM_notify_me' ); #} can put actual settings in here later (for now just have it notify them regardless). -function zeroBSCRM_notifyme_settings(){} - +function zeroBSCRM_notifyme_settings() {} -function zeroBSCRM_notifyme_echo_type($type = '', $title = '', $sender = -999, $content = ''){ +function zeroBSCRM_notifyme_echo_type( $type = '', $title = '', $sender = -999, $content = '' ) { - global $zbs; + global $zbs; - switch ($type) { + switch ( $type ) { - case 'migration.blocked.errors': - esc_html_e("There has been a general error with CRM migrations, a single migration appears to be blocked. Please contact support.", "zero-bs-crm"); - break; + case 'migration.blocked.errors': + esc_html_e( 'There has been a general error with CRM migrations, a single migration appears to be blocked. Please contact support.', 'zero-bs-crm' ); + break; - case 'woosync.suggestion': - esc_html_e("🎯 we have detected that you are running WooCommerce. We have a kick ass extension for that. ", "zero-bs-crm"); - break; + case 'woosync.suggestion': + esc_html_e( '🎯 we have detected that you are running WooCommerce. We have a kick ass extension for that. ', 'zero-bs-crm' ); + break; - case 'salesdash.suggestion': + case 'salesdash.suggestion': echo esc_html( __( '⛽ See all your sales information in a sales dashboard built just for you.', 'zero-bs-crm' ) . ' ' ); - break; - - - case 'notifications.suggestion': - echo wp_kses( sprintf( __( '🔔 Want notifications PRO? This is coming soon to our Entrepreneur Bundle. Get it while it\'s hot!', 'zero-bs-crm' ), esc_url( $zbs->urls['upgrade'] ) ), $zbs->acceptable_restricted_html ) . ' '; - break; - - case 'extension.update': - ##WLREMOVE - echo wp_kses( sprintf( __( '🔔 [URGENT] Your extension(s) need updating Click here to retrieve the new versions. (If you don\'t know your login, please Email Support.)', 'zero-bs-crm' ), esc_url( $zbs->urls['account'] ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); - ##/WLREMOVE - break; - - // v2.70 - DB2 contacts migration :) - case 'db2.update.253': - echo esc_html( sprintf( __( '🔔 [URGENT] Your Contact Database needs migrating. Running this database update will increase your CRM load-times by up to 60x!', 'zero-bs-crm' ) ) ); - break; - - // v2.70 - DB2 contacts migration :) FINI - case 'db2.update.253.success': - echo wp_kses( sprintf( __('Your contact database was successfully migrated. Please update any PRO Extensions you may have installed.',"zero-bs-crm" ), esc_url( $zbs->urls['products'] ) ), $zbs->acceptable_restricted_html ); - break; - - // v2.70 - DB2 contacts migration :) FINI - case 'db2.update.253.errors': - - // load errs - $zbsMigrationErrors = get_option( 'zbs_db_migration_253_errors', -1); - $errStr = ''; if (isset($zbsMigrationErrors) && is_array($zbsMigrationErrors)) foreach ($zbsMigrationErrors as $zme) $errStr .= '
'.$zme; - - echo sprintf( __( 'Jetpack CRM has tried to update your core CRM to 2.70 but hit errors. Please send the following error report to Support:
Migration Error Report:%s Contact Support', "zero-bs-crm" ), $errStr, esc_url( $zbs->urls['support'] ) ); - break; - - // v2.70 - DB2 contacts migration :) FINI + has extensions to update - case 'db2.extupdate.253': - ##WLREMOVE - echo wp_kses( sprintf( __( 'Please Update your Extensions (DB Migration makes this essential!) View Extension Updates', "zero-bs-crm" ), jpcrm_esc_link( $zbs->slugs['connect'] ) ), $zbs->acceptable_restricted_html ); - ##/WLREMOVE - break; - - case 'extension.new.update.avail': - ##WLREMOVE - echo wp_kses( sprintf( __( '🔔 One or more of your extensions need updating. Please update to avoid any issues with security or compatibility Learn More.', "zero-bs-crm" ), esc_url( admin_url('admin.php?page=zerobscrm-connect')) ), $zbs->acceptable_restricted_html ); - ##/WLREMOVE - break; - - case 'license.update.needed': - echo '⚠️ ' . $content; - break; - - case 'general.extension.update.needed': - echo '⚠️ ' . $content; - break; - - // 2.94.2 - smtp mode changed, need to tell peeps to revalidate - case 'smtp.2943.needtocheck': - echo sprintf( __( 'Important: 🔔 Jetpack CRM has just updated the way it handles SMTP Delivery Methods.
Please check each of your Delivery Methods still works by loading Mail Delivery Methods and clicking \'send test\', validating that it still sends', 'zero-bs-crm' ), esc_url( admin_url('admin.php?page=zerobscrm-plugin-settings&tab=maildelivery') ) ); - break; - - // 3.0.17 - Changed the password encryption, so get people to validate - case 'smtp.3017.needtocheck': - echo sprintf( __( 'Important: 🔔 Jetpack CRM has improved the encryption of SMTP passwords.
Please check each of your Delivery Methods still works by loading Mail Delivery Methods and clicking \'send test\', validating that it still sends', 'zero-bs-crm' ), jpcrm_esc_link( $zbs->slugs['settings'] . '&tab=maildelivery' ) ); - break; - - - //now do the extension updates like this - - case 'custom.extension.update.needed': - $x = __("🔔","zero-bs-crm") . $content . ' ' . __("Update Now", "zero-bs-crm") . '.'; - - ##WLREMOVE - $x = __("🔔","zero-bs-crm") . $content . ' ' . __("Update Now", "zero-bs-crm") . '.'; - ##/WLREMOVE - echo $x; - break; - //now do the extension updates like this - // this is WL CORE update - case 'core.update.needed': - - echo esc_html__("🔔","zero-bs-crm") . $content . ' ' . esc_html__("Update Now", "zero-bs-crm") . '.'; - - break; - - - // 4.5.0 - Missing template file - case 'missing.template': - echo wp_kses( __( 'Template File Error:
It was not possible to load the following template file. This will mean that related documents will not be loaded properly.
Template File: ', 'zero-bs-crm' ), $zbs->acceptable_restricted_html ) . $content; - break; - - // ========= v5+ MIGRATIONS - - // v5.1 - migrate woosync sites - case 'woosync.5.1.migration': - - echo esc_html__( 'WooSync was unable to migrate settings (5.2). Sync will be stopped until this is remedied.', 'zero-bs-crm' ) . ' ' . wp_kses( sprintf( __( 'Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); - - break; - // ========= / v5+ MIGRATIONS - - // ========= Exceptions seen - - // Segment audience tried to build but some conditions produced no arguments - // (likely segment created with adv segments active, then adv segments been deactivated) - case 'segments.orphaned.conditions': - - echo esc_html__( '⚠️ A segment was retrieved which has conditions which produced no arguments. (This usually happens when a segment was made via Advanced Segments extension, then that extension is deactivated). Please reactivate any segment extending plugins you have, or contact support.', "zero-bs-crm" ); - break; - - // ========= / Exceptions seen - - // ========= MC2 - case 'campaign.paused.due.to.error': - - echo esc_html__( 'A mail campaign has been paused due to an error.', 'zero-bs-crm' ) . '    ' . $content; - - break; - case 'campaign.can.be.unpaused': - - echo esc_html__( 'A mail campaign which was previously blocked from sending by an error is now able to send. Please unpause the campaign to continue to send.', 'zero-bs-crm' ) . '    ' . $content; - - break; - // ========= / MC2 - - // ========= WooSync - case 'woosync.conflict.deactivated': - - echo wp_kses( sprintf( __( 'Your standalone WooSync extension has been deactivated; WooSync is now in the core CRM! Read more', 'zero-bs-crm' ), esc_url( $zbs->urls['v5announce'] ) ), $zbs->acceptable_restricted_html ); - - break; - case 'woosync.syncsite.paused': - - echo wp_kses( sprintf( __( 'Your WooSync Store connection has been paused due to three errors in connecting to the store. View Connections', 'zero-bs-crm' ), esc_url( $content ) ), $zbs->acceptable_restricted_html ); - - break; - // ========= / WooSync + break; + + case 'notifications.suggestion': + echo wp_kses( sprintf( __( '🔔 Want notifications PRO? This is coming soon to our Entrepreneur Bundle. Get it while it\'s hot!', 'zero-bs-crm' ), esc_url( $zbs->urls['upgrade'] ) ), $zbs->acceptable_restricted_html ) . ' '; + break; + + case 'extension.update': + ##WLREMOVE + echo wp_kses( sprintf( __( '🔔 [URGENT] Your extension(s) need updating Click here to retrieve the new versions. (If you don\'t know your login, please Email Support.)', 'zero-bs-crm' ), esc_url( $zbs->urls['account'] ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); + ##/WLREMOVE + break; + + // v2.70 - DB2 contacts migration :) + case 'db2.update.253': + echo esc_html( sprintf( __( '🔔 [URGENT] Your Contact Database needs migrating. Running this database update will increase your CRM load-times by up to 60x!', 'zero-bs-crm' ) ) ); + break; + + // v2.70 - DB2 contacts migration :) FINI + case 'db2.update.253.success': + echo wp_kses( sprintf( __( 'Your contact database was successfully migrated. Please update any PRO Extensions you may have installed.', 'zero-bs-crm' ), esc_url( $zbs->urls['products'] ) ), $zbs->acceptable_restricted_html ); + break; + + // v2.70 - DB2 contacts migration :) FINI + case 'db2.update.253.errors': + // load errs + $zbsMigrationErrors = get_option( 'zbs_db_migration_253_errors', -1 ); + $errStr = ''; + if ( isset( $zbsMigrationErrors ) && is_array( $zbsMigrationErrors ) ) { + foreach ( $zbsMigrationErrors as $zme ) { + $errStr .= '
' . $zme; + } + } + + printf( __( 'Jetpack CRM has tried to update your core CRM to 2.70 but hit errors. Please send the following error report to Support:
Migration Error Report:%1$s Contact Support', 'zero-bs-crm' ), $errStr, esc_url( $zbs->urls['support'] ) ); + break; + + // v2.70 - DB2 contacts migration :) FINI + has extensions to update + case 'db2.extupdate.253': + ##WLREMOVE + echo wp_kses( sprintf( __( 'Please Update your Extensions (DB Migration makes this essential!) View Extension Updates', 'zero-bs-crm' ), jpcrm_esc_link( $zbs->slugs['connect'] ) ), $zbs->acceptable_restricted_html ); + ##/WLREMOVE + break; + + case 'extension.new.update.avail': + ##WLREMOVE + echo wp_kses( sprintf( __( '🔔 One or more of your extensions need updating. Please update to avoid any issues with security or compatibility Learn More.', 'zero-bs-crm' ), esc_url( admin_url( 'admin.php?page=zerobscrm-connect' ) ) ), $zbs->acceptable_restricted_html ); + ##/WLREMOVE + break; + + case 'license.update.needed': + echo '⚠️ ' . $content; + break; + + case 'general.extension.update.needed': + echo '⚠️ ' . $content; + break; + + // 2.94.2 - smtp mode changed, need to tell peeps to revalidate + case 'smtp.2943.needtocheck': + printf( __( 'Important: 🔔 Jetpack CRM has just updated the way it handles SMTP Delivery Methods.
Please check each of your Delivery Methods still works by loading Mail Delivery Methods and clicking \'send test\', validating that it still sends', 'zero-bs-crm' ), esc_url( admin_url( 'admin.php?page=zerobscrm-plugin-settings&tab=maildelivery' ) ) ); + break; + + // 3.0.17 - Changed the password encryption, so get people to validate + case 'smtp.3017.needtocheck': + printf( __( 'Important: 🔔 Jetpack CRM has improved the encryption of SMTP passwords.
Please check each of your Delivery Methods still works by loading Mail Delivery Methods and clicking \'send test\', validating that it still sends', 'zero-bs-crm' ), jpcrm_esc_link( $zbs->slugs['settings'] . '&tab=maildelivery' ) ); + break; + + // now do the extension updates like this + + case 'custom.extension.update.needed': + $x = __( '🔔', 'zero-bs-crm' ) . $content . ' ' . __( 'Update Now', 'zero-bs-crm' ) . '.'; + + ##WLREMOVE + $x = __( '🔔', 'zero-bs-crm' ) . $content . ' ' . __( 'Update Now', 'zero-bs-crm' ) . '.'; + ##/WLREMOVE + echo $x; + break; + // now do the extension updates like this + // this is WL CORE update + case 'core.update.needed': + echo esc_html__( '🔔', 'zero-bs-crm' ) . $content . ' ' . esc_html__( 'Update Now', 'zero-bs-crm' ) . '.'; + + break; + + // 4.5.0 - Missing template file + case 'missing.template': + echo wp_kses( __( 'Template File Error:
It was not possible to load the following template file. This will mean that related documents will not be loaded properly.
Template File: ', 'zero-bs-crm' ), $zbs->acceptable_restricted_html ) . $content; + break; + + // ========= v5+ MIGRATIONS + + // v5.1 - migrate woosync sites + case 'woosync.5.1.migration': + echo esc_html__( 'WooSync was unable to migrate settings (5.2). Sync will be stopped until this is remedied.', 'zero-bs-crm' ) . ' ' . wp_kses( sprintf( __( 'Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); + + break; + // ========= / v5+ MIGRATIONS + + // ========= Exceptions seen + + // Segment audience tried to build but some conditions produced no arguments + // (likely segment created with adv segments active, then adv segments been deactivated) + case 'segments.orphaned.conditions': + echo esc_html__( '⚠️ A segment was retrieved which has conditions which produced no arguments. (This usually happens when a segment was made via Advanced Segments extension, then that extension is deactivated). Please reactivate any segment extending plugins you have, or contact support.', 'zero-bs-crm' ); + break; + + // ========= / Exceptions seen + + // ========= MC2 + case 'campaign.paused.due.to.error': + echo esc_html__( 'A mail campaign has been paused due to an error.', 'zero-bs-crm' ) . '    ' . $content; + + break; + case 'campaign.can.be.unpaused': + echo esc_html__( 'A mail campaign which was previously blocked from sending by an error is now able to send. Please unpause the campaign to continue to send.', 'zero-bs-crm' ) . '    ' . $content; + + break; + // ========= / MC2 + + // ========= WooSync + case 'woosync.conflict.deactivated': + echo wp_kses( sprintf( __( 'Your standalone WooSync extension has been deactivated; WooSync is now in the core CRM! Read more', 'zero-bs-crm' ), esc_url( $zbs->urls['v5announce'] ) ), $zbs->acceptable_restricted_html ); + + break; + case 'woosync.syncsite.paused': + echo wp_kses( sprintf( __( 'Your WooSync Store connection has been paused due to three errors in connecting to the store. View Connections', 'zero-bs-crm' ), esc_url( $content ) ), $zbs->acceptable_restricted_html ); - // ========= Client Portal Pro - case 'clientportalpro.incompatible.version.deactivated': + break; + // ========= / WooSync - echo esc_html__( 'You are using an outdated version of the Client Portal Pro extension, which is not compatible with this version of the CRM. It has been deactivated. Please update the extension to continue using Client Portal Pro.', 'zero-bs-crm' ); + // ========= Client Portal Pro + case 'clientportalpro.incompatible.version.deactivated': + echo esc_html__( 'You are using an outdated version of the Client Portal Pro extension, which is not compatible with this version of the CRM. It has been deactivated. Please update the extension to continue using Client Portal Pro.', 'zero-bs-crm' ); - break; - // ========= / Client Portal Pro + break; + // ========= / Client Portal Pro - // ========= Package Installer - case 'package.installer.fail_count_over': + // ========= Package Installer + case 'package.installer.fail_count_over': + echo sprintf( __( 'Package Installer was not able to install the requested package %s, after trying the maximum number of times.', 'zero-bs-crm' ), $content ) . wp_kses( sprintf( __( ' Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); - echo sprintf( __( 'Package Installer was not able to install the requested package %s, after trying the maximum number of times.', 'zero-bs-crm' ), $content ) . wp_kses( sprintf( __( ' Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); + break; + case 'package.installer.dir_create_error': + echo sprintf( __( 'Package Installer could not create directories needed to install the package %s.', 'zero-bs-crm' ), $content ) . wp_kses( sprintf( __( ' Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); - break; - case 'package.installer.dir_create_error': + break; + case 'package.installer.unzip_error': + echo sprintf( __( 'Package Installer was not able to expand the requested package zip file for the package %s', 'zero-bs-crm' ), $content ) . wp_kses( sprintf( __( ' Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); - echo sprintf( __( 'Package Installer could not create directories needed to install the package %s.', 'zero-bs-crm' ), $content ) . wp_kses( sprintf( __( ' Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); + break; + case 'package.installer.dl_error': + echo sprintf( __( 'Package Installer was not able to download the requested package %s', 'zero-bs-crm' ), $content ) . wp_kses( sprintf( __( ' Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); - break; - case 'package.installer.unzip_error': + break; + case 'curl.timeout.error': + printf( __( 'Failed to retrieve key file, your server may not be able to connect to the CRM CDN: %s. If this message persists, please contact support', 'zero-bs-crm' ), $content ); - echo sprintf( __( 'Package Installer was not able to expand the requested package zip file for the package %s', 'zero-bs-crm' ), $content ) . wp_kses( sprintf( __( ' Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); - - break; - case 'package.installer.dl_error': - - echo sprintf( __( 'Package Installer was not able to download the requested package %s', 'zero-bs-crm' ), $content ) . wp_kses( sprintf( __( ' Please contact support.', 'zero-bs-crm' ), esc_url( $zbs->urls['support'] ) ), $zbs->acceptable_restricted_html ); - - break; - case 'curl.timeout.error': - - echo sprintf( __( 'Failed to retrieve key file, your server may not be able to connect to the CRM CDN: %s. If this message persists, please contact support', 'zero-bs-crm' ), $content ); - - break; - // ========= / Package Installer + break; + // ========= / Package Installer default: esc_html_e( 'Unable to load notification.', 'zero-bs-crm' ); } } -function zeroBSCRM_notifyme_time_ago($datetime){ - if (is_numeric($datetime)) { - $timestamp = $datetime; - } else { - $timestamp = strtotime($datetime); - } - $diff=time()-$timestamp; - - $min=60; - $hour=60*60; - $day=60*60*24; - $month=$day*30; - - if($diff<60) //Under a min - { - $timeago = $diff . " seconds"; - }elseif ($diff<$hour) //Under an hour - { - $timeago = round($diff/$min) . " mins"; - }elseif ($diff<$day) //Under a day - { - $timeago = round($diff/$hour) . " hours"; - }elseif ($diff<$month) //Under a day - { - $timeago = round($diff/$day) . " days"; - }else - { - $timeago = round($diff/$month) ." months"; - } - - return $timeago; +function zeroBSCRM_notifyme_time_ago( $datetime ) { + if ( is_numeric( $datetime ) ) { + $timestamp = $datetime; + } else { + $timestamp = strtotime( $datetime ); + } + $diff = time() - $timestamp; + + $min = 60; + $hour = 60 * 60; + $day = 60 * 60 * 24; + $month = $day * 30; + + if ( $diff < 60 ) { + $timeago = $diff . ' seconds'; + } elseif ( $diff < $hour ) { + $timeago = round( $diff / $min ) . ' mins'; + } elseif ( $diff < $day ) { + $timeago = round( $diff / $hour ) . ' hours'; + } elseif ( $diff < $month ) { + $timeago = round( $diff / $day ) . ' days'; + } else { + $timeago = round( $diff / $month ) . ' months'; + } + + return $timeago; } -//function to insert the notification into the database.. +// function to insert the notification into the database.. /* + $recipient = get_current_user_id(); i.e. WHO are we notifying (WP_user ID) + $sender = -999; //in this case... we can call ZBS our -999 user ID (for bot icon stuff) and output our icon where it's system stuff. + $post_id = 0; //i.e. not a post related activity (but can pass $post_id for linking to various pages) - NOT USED + ^^ use that in notifications PRO to store edit links for customerID, invoiceID, etc. but with new DB this is effectively the ID of whatever + $type = 'woosync.suggestion'; //this is a extension suggestion type, see zeroBSCRM_notifyme_echo_type + for the switch / case here. Store the InternalAutomator actions strings here and extend where we want to notify of that.. e.g. 10 new leads have been added since you last logged in. + /* DOESN'T DO - $recipient = get_current_user_id(); i.e. WHO are we notifying (WP_user ID) - $sender = -999; //in this case... we can call ZBS our -999 user ID (for bot icon stuff) and output our icon where it's system stuff. - $post_id = 0; //i.e. not a post related activity (but can pass $post_id for linking to various pages) - NOT USED - ^^ use that in notifications PRO to store edit links for customerID, invoiceID, etc. but with new DB this is effectively the ID of whatever - $type = 'woosync.suggestion'; //this is a extension suggestion type, see zeroBSCRM_notifyme_echo_type - for the switch / case here. Store the InternalAutomator actions strings here and extend where we want to notify of that.. e.g. 10 new leads have been added since you last logged in. - - /* DOESN'T DO + - GROUPING of similar notifications. If you do have it to notify on new customer it will show a notification line for each and every one. Rather than "100 new contact since your last visit" it would show [name1 .. name100] has been added as a new conact, 100 times - - GROUPING of similar notifications. If you do have it to notify on new customer it will show a notification line for each and every one. Rather than "100 new contact since your last visit" it would show [name1 .. name100] has been added as a new conact, 100 times + - SNOOZING of notifications. They're ALWAYS on. - - SNOOZING of notifications. They're ALWAYS on. - - // zeroBSCRM_notifyme_insert_notification($recipient,$sender,$post_id,$type); + // zeroBSCRM_notifyme_insert_notification($recipient,$sender,$post_id,$type); */ -function zeroBSCRM_notifyme_insert_notification($recipient = -1, $sender = -999, $post_id = -1, $type = '', $parameters = '', $reference = -1){ - global $wpdb; - $notify_table = $wpdb->prefix . "zbs_notifications"; - $now = time(); - - // * WH NOTE: - // ownership needed DBv2+ - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, - // OWNER was not_null so I've added -1 for now :) to add these 3 when makes sense - - #} only stores if the recipient is NOT the user - if($recipient != $sender){ - - //need to check first whether the reference ID already exists (add with a UNIQUE REFERENCEID going forwards) - - //"parameters" here is really the content of the notification... $reference is the unique ID - //added new "type" of custom.extension.update.needed - - // if $parameters is empty seems to bug out :) so forcing it to be smt if empty: - if (empty($parameters)) $parameters = '-1'; - if (empty($type)) $type = '-1'; - - $sql = $wpdb->prepare("SELECT id FROM $notify_table WHERE zbsnotify_reference_id = %d AND zbsnotify_parameters = %s", $reference, $parameters); - $results = $wpdb->get_results($sql); - - if(count($results) == 0){ - $sql = $wpdb->prepare("INSERT INTO $notify_table ( zbs_owner, zbsnotify_recipient_id , zbsnotify_sender_id, zbsnotify_unread, zbsnotify_type, zbsnotify_parameters, zbsnotify_reference_id, zbsnotify_created_at) VALUES ( %d, %d, %d, %d, %s, %s, %d, %s)", -1, $recipient, $sender, '0', $type, $parameters, $reference, $now); - $wpdb->query($sql); - } - } +function zeroBSCRM_notifyme_insert_notification( $recipient = -1, $sender = -999, $post_id = -1, $type = '', $parameters = '', $reference = -1 ) { + global $wpdb; + $notify_table = $wpdb->prefix . 'zbs_notifications'; + $now = time(); + + // * WH NOTE: + // ownership needed DBv2+ + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, + // OWNER was not_null so I've added -1 for now :) to add these 3 when makes sense + + #} only stores if the recipient is NOT the user + if ( $recipient != $sender ) { + + // need to check first whether the reference ID already exists (add with a UNIQUE REFERENCEID going forwards) + + // "parameters" here is really the content of the notification... $reference is the unique ID + // added new "type" of custom.extension.update.needed + + // if $parameters is empty seems to bug out :) so forcing it to be smt if empty: + if ( empty( $parameters ) ) { + $parameters = '-1'; + } + if ( empty( $type ) ) { + $type = '-1'; + } + + $sql = $wpdb->prepare( "SELECT id FROM $notify_table WHERE zbsnotify_reference_id = %d AND zbsnotify_parameters = %s", $reference, $parameters ); + $results = $wpdb->get_results( $sql ); + + if ( count( $results ) == 0 ) { + $sql = $wpdb->prepare( "INSERT INTO $notify_table ( zbs_owner, zbsnotify_recipient_id , zbsnotify_sender_id, zbsnotify_unread, zbsnotify_type, zbsnotify_parameters, zbsnotify_reference_id, zbsnotify_created_at) VALUES ( %d, %d, %d, %d, %s, %s, %d, %s)", -1, $recipient, $sender, '0', $type, $parameters, $reference, $now ); + $wpdb->query( $sql ); + } + } } +function zeroBSCRM_notifyme_activity() { + global $wpdb; + $cid = get_current_user_id(); -function zeroBSCRM_notifyme_activity(){ - global $wpdb; - $cid = get_current_user_id(); - - // * WH NOTE: - // ownership needed DBv2+ - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, + // * WH NOTE: + // ownership needed DBv2+ + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, - $notify_table = $wpdb->prefix . "zbs_notifications"; - $sql = $wpdb->prepare("SELECT * FROM $notify_table WHERE zbsnotify_recipient_id = %d ORDER BY zbsnotify_created_at DESC LIMIT 20", $cid); - $notifes = $wpdb->get_results($sql); + $notify_table = $wpdb->prefix . 'zbs_notifications'; + $sql = $wpdb->prepare( "SELECT * FROM $notify_table WHERE zbsnotify_recipient_id = %d ORDER BY zbsnotify_created_at DESC LIMIT 20", $cid ); + $notifes = $wpdb->get_results( $sql ); - echo '
'; + echo '
'; - if(count($notifes) == 0){ + if ( count( $notifes ) == 0 ) { - // EXAMPLE NOTIFICATION - FOR THE TOUR :-) - $notify_logo_url = jpcrm_get_logo(); + // EXAMPLE NOTIFICATION - FOR THE TOUR :-) + $notify_logo_url = jpcrm_get_logo(); - $sender_avatar = ""; + $sender_avatar = ""; $another_notty = __( 'Here is another notification example from John Doe.', 'zero-bs-crm' ); - echo "'; - echo '
'; - - echo "
"; - echo '
'; - echo $sender_avatar; - echo '
'; - echo '
'; - esc_html_e("This is an example notification. Here is where you will be kept notified :) simple. effective.", "zero-bs-crm"); - echo "
"; - echo '
'; - esc_html_e("Just now", "zero-bs-crm"); - echo '
'; - echo '
'; - - + echo "'; + echo '
'; + + echo "
"; + echo '
'; + echo $sender_avatar; + echo '
'; + echo '
'; + esc_html_e( 'This is an example notification. Here is where you will be kept notified :) simple. effective.', 'zero-bs-crm' ); + echo '
'; + echo '
'; + esc_html_e( 'Just now', 'zero-bs-crm' ); + echo '
'; + echo '
'; + + } else { + + foreach ( $notifes as $n ) { + + $title = ''; // can pass specific title to the echo function + $sender = $n->zbsnotify_sender_id; + + if ( $sender == -999 ) { + // this is our "ZBS notifications bot". This sniffs around WP checking everything is OK.. and also lets + // them know about any updates we have pinged out from our own JSON file on https:// :-) ... POW ERRRR FULL + $notify_logo_url = jpcrm_get_logo(); + $sender_avatar = ""; + } else { + $sender_avatar = jpcrm_get_avatar( $n->zbsnotify_sender_id, 30 ); + } + + $sender_url = ''; + if ( isset( $n ) && isset( $n->sender_id ) ) { + $sender_url = get_author_posts_url( $n->sender_id ); + } + + echo "
"; + echo '
'; + echo $sender_avatar; + echo '
'; + echo '
'; + zeroBSCRM_notifyme_echo_type( $n->zbsnotify_type, $title, $n->zbsnotify_sender_id, $n->zbsnotify_parameters ); + echo '
'; + echo '
'; + esc_html_e( zeroBSCRM_notifyme_time_ago( $n->zbsnotify_created_at ) . ' ago ', 'zero-bs-crm' ); + echo '
'; + echo '
'; + echo '
'; + + } + + echo '
'; + } - }else{ - - foreach($notifes as $n){ - - $title = ''; //can pass specific title to the echo function - $sender = $n->zbsnotify_sender_id; - - if($sender == -999){ - //this is our "ZBS notifications bot". This sniffs around WP checking everything is OK.. and also lets - //them know about any updates we have pinged out from our own JSON file on https:// :-) ... POW ERRRR FULL - $notify_logo_url = jpcrm_get_logo(); - $sender_avatar = ""; - }else{ - $sender_avatar = jpcrm_get_avatar( $n->zbsnotify_sender_id, 30); - } - - - $sender_url = ''; if (isset($n) && isset($n->sender_id)) $sender_url = get_author_posts_url($n->sender_id); - - - echo "
"; - echo '
'; - echo $sender_avatar; - echo '
'; - echo '
'; - zeroBSCRM_notifyme_echo_type($n->zbsnotify_type, $title, $n->zbsnotify_sender_id, $n->zbsnotify_parameters); - echo "
"; - echo '
'; - esc_html_e(zeroBSCRM_notifyme_time_ago($n->zbsnotify_created_at) . " ago ", "zero-bs-crm"); - echo '
'; - echo '
'; - echo '
'; - - - } - - echo "
"; - - } - - //got here. Mark the notifications as read for this user :-) - $sql = $wpdb->prepare("UPDATE $notify_table SET zbsnotify_unread = %d WHERE zbsnotify_recipient_id = %d", 1, $cid); - $wpdb->query($sql); - + // got here. Mark the notifications as read for this user :-) + $sql = $wpdb->prepare( "UPDATE $notify_table SET zbsnotify_unread = %d WHERE zbsnotify_recipient_id = %d", 1, $cid ); + $wpdb->query( $sql ); } - - -add_action('wp_ajax_nopriv_notifyme_get_notifications_ajax','zeroBSCRM_notifyme_get_notifications_ajax'); +add_action( 'wp_ajax_nopriv_notifyme_get_notifications_ajax', 'zeroBSCRM_notifyme_get_notifications_ajax' ); add_action( 'wp_ajax_notifyme_get_notifications_ajax', 'zeroBSCRM_notifyme_get_notifications_ajax' ); -function zeroBSCRM_notifyme_get_notifications_ajax(){ +function zeroBSCRM_notifyme_get_notifications_ajax() { global $wpdb; $res = array(); - check_ajax_referer( 'notifyme_nonce', 'security' ); - $cid = get_current_user_id(); - $now = date("U"); - $notify_table = $wpdb->prefix . "zbs_notifications"; - - // * WH NOTE: - // ownership needed DBv2+ - // no need to update these (as of yet) - can't move teams etc. - //'zbs_site' => zeroBSCRM_installSite(), - //'zbs_team' => zeroBSCRM_installTeam(), - //'zbs_owner' => $owner, - - $sql = $wpdb->prepare("SELECT * FROM $notify_table WHERE zbsnotify_recipient_id = %d AND zbsnotify_unread = %d", $cid, 0); - $notifes = $wpdb->get_results($sql); - $res['count'] = 0; - - $res['notifications'] = $notifes; - if(!$notifes){ - $res['count'] = 0; - }else{ - $res['message'] = "Passed AJAX nonce check"; - $res['notifytitle'] = 'This is the title'; - $res['notifybody'] = 'This is the body'; - $res['count'] = count($res['notifications']); - } + check_ajax_referer( 'notifyme_nonce', 'security' ); + $cid = get_current_user_id(); + $now = date( 'U' ); + $notify_table = $wpdb->prefix . 'zbs_notifications'; + + // * WH NOTE: + // ownership needed DBv2+ + // no need to update these (as of yet) - can't move teams etc. + // 'zbs_site' => zeroBSCRM_installSite(), + // 'zbs_team' => zeroBSCRM_installTeam(), + // 'zbs_owner' => $owner, + + $sql = $wpdb->prepare( "SELECT * FROM $notify_table WHERE zbsnotify_recipient_id = %d AND zbsnotify_unread = %d", $cid, 0 ); + $notifes = $wpdb->get_results( $sql ); + $res['count'] = 0; + + $res['notifications'] = $notifes; + if ( ! $notifes ) { + $res['count'] = 0; + } else { + $res['message'] = 'Passed AJAX nonce check'; + $res['notifytitle'] = 'This is the title'; + $res['notifybody'] = 'This is the body'; + $res['count'] = count( $res['notifications'] ); + } wp_send_json( $res ); } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.PerformanceTesting.php b/projects/plugins/crm/includes/ZeroBSCRM.PerformanceTesting.php index 8d28adb2d697..cdbec7db4ae6 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.PerformanceTesting.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.PerformanceTesting.php @@ -1,164 +1,173 @@ -1,'end'=>-1); + global $zbsTimes; + if ( ! isset( $zbsTimes[ $key ] ) || ! is_array( $zbsTimes[ $key ] ) ) { + $zbsTimes[ $key ] = array( + 'start' => -1, + 'end' => -1, + ); + } - #} start it - $zbsTimes[$key]['start'] = microtime(true); + #} start it + $zbsTimes[ $key ]['start'] = microtime( true ); - } + } - return false; + return false; +} +function zeroBSCRM_performanceTest_finishTimer( $key = '' ) { - } - function zeroBSCRM_performanceTest_finishTimer($key=''){ + if ( ! empty( $key ) ) { - if (!empty($key)){ + global $zbsTimes; - global $zbsTimes; - - #} end it - lazy, no cheeck - $zbsTimes[$key]['end'] = microtime(true); + #} end it - lazy, no cheeck + $zbsTimes[ $key ]['end'] = microtime( true ); - } + } - return false; + return false; +} - } + // returns singular results for 1 timer + // (used by debugger plugin) +function zeroBSCRM_performanceTest_results( $key = '' ) { - // returns singular results for 1 timer - // (used by debugger plugin) - function zeroBSCRM_performanceTest_results($key=''){ + if ( ! empty( $key ) ) { + global $zbsTimes; - if (!empty($key)){ + if ( is_array( $zbsTimes ) && isset( $zbsTimes[ $key ] ) ) { - global $zbsTimes; + $v = $zbsTimes[ $key ]; - if (is_array($zbsTimes) && isset($zbsTimes[$key])){ + $time_start = -1; + if ( isset( $v['start'] ) ) { + $time_start = $v['start']; + } + $time_end = -1; + if ( isset( $v['end'] ) ) { + $time_end = $v['end']; + } - $v = $zbsTimes[$key]; - - $time_start = -1; if (isset($v['start'])) $time_start = $v['start']; - $time_end = -1; if (isset($v['end'])) $time_end = $v['end']; + $sTime = -1; + $sTimeExtra = ''; + if ( $time_start > -1 && $time_end > -1 ) { + $sTime = round( ( $time_end - $time_start ), 3 ); + } else { - $sTime = -1; $sTimeExtra = ''; - if ($time_start > -1 && $time_end > -1) { - $sTime = round(($time_end - $time_start),3); - } else { + // one hasn't been set + if ( $time_end == -1 && $time_start > -1 ) { - // one hasn't been set - if ($time_end == -1 && $time_start > -1){ + $sTime = round( ( microtime( true ) - $time_start ), 3 ); + $sTimeExtra = '+ (still running)'; - $sTime = round((microtime(true)-$time_start),3); - $sTimeExtra ='+ (still running)'; - - } else { + } else { - $sTimeExtra = '???'; + $sTimeExtra = '???'; - } } - - return $sTime.$sTimeExtra; - } - } - - return false; + return $sTime . $sTimeExtra; - } + } + } - function zeroBSCRM_performanceTest_debugOut(){ + return false; +} - global $zbsTimes; +function zeroBSCRM_performanceTest_debugOut() { - // debug - echo '

CRM Performance Debug

'; - $scriptVer = 'console.log("=============== CRM Performance Debug ==============");'; - foreach ($zbsTimes as $k => $v) { + global $zbsTimes; - $time_start = -1; if (isset($v['start'])) $time_start = $v['start']; - $time_end = -1; if (isset($v['end'])) $time_end = $v['end']; + // debug + echo '

CRM Performance Debug

'; + $scriptVer = 'console.log("=============== CRM Performance Debug ==============");'; + foreach ( $zbsTimes as $k => $v ) { - $sTime = -1; $sTimeExtra = ''; - if ($time_start > -1 && $time_end > -1) { - $sTime = round(($time_end - $time_start),3); - } else { + $time_start = -1; + if ( isset( $v['start'] ) ) { + $time_start = $v['start']; + } + $time_end = -1; + if ( isset( $v['end'] ) ) { + $time_end = $v['end']; + } - // one hasn't been set - if ($time_end == -1 && $time_start > -1){ + $sTime = -1; + $sTimeExtra = ''; + if ( $time_start > -1 && $time_end > -1 ) { + $sTime = round( ( $time_end - $time_start ), 3 ); + } else { - $sTime = round((microtime(true)-$time_start),3); - $sTimeExtra ='+ (still running)'; - - } else { + // one hasn't been set + if ( $time_end == -1 && $time_start > -1 ) { - $sTimeExtra = '???'; + $sTime = round( ( microtime( true ) - $time_start ), 3 ); + $sTimeExtra = '+ (still running)'; - } - } + } else { - echo '

Time: '.$k.'

'; - echo '

'.$sTime.$sTimeExtra.' seconds

'; - $retArr = $v; - $retArr['took'] = $sTime; - $scriptVer .= 'console.log("'.$k.': '.$sTime.$sTimeExtra.'",'.json_encode($retArr).');'; + $sTimeExtra = '???'; + } } - echo '
'; - echo ''; - - } - - #} Start a global timer :) - zeroBSCRM_performanceTest_startTimer('postinc'); - + echo '

Time: ' . $k . '

'; + echo '

' . $sTime . $sTimeExtra . ' seconds

'; + $retArr = $v; + $retArr['took'] = $sTime; + $scriptVer .= 'console.log("' . $k . ': ' . $sTime . $sTimeExtra . '",' . json_encode( $retArr ) . ');'; + } + echo '
'; + echo ''; +} + #} Start a global timer :) + zeroBSCRM_performanceTest_startTimer( 'postinc' ); // ==================================================================== // ==================== General Perf Testing ========================== - function zeroBSCRM_performanceTest_closeGlobalTest($key=''){ +function zeroBSCRM_performanceTest_closeGlobalTest( $key = '' ) { - if (defined('ZBSPERFTEST')) { - if (!empty($key)){ + if ( defined( 'ZBSPERFTEST' ) ) { + if ( ! empty( $key ) ) { - // retrieve our global (may have had any number of test res added) - global $zbsPerfTest; + // retrieve our global (may have had any number of test res added) + global $zbsPerfTest; - // finish timer - zeroBSCRM_performanceTest_finishTimer($key); + // finish timer + zeroBSCRM_performanceTest_finishTimer( $key ); - // store in perf-reports - $zbsPerfTest['results'][$key] = zeroBSCRM_performanceTest_results($key); + // store in perf-reports + $zbsPerfTest['results'][ $key ] = zeroBSCRM_performanceTest_results( $key ); - } - } + } + } +} - } - /* - This got abbreviated with above: @@ -170,7 +179,7 @@ function zeroBSCRM_performanceTest_closeGlobalTest($key=''){ global $zbsPerfTest; // start timer (will need a 'catch + add' for this at end of whatever this is timing) - zeroBSCRM_performanceTest_startTimer('includes'); + zeroBSCRM_performanceTest_startTimer('includes'); } // =================== / General Perf Testing ========================= diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Permissions.php b/projects/plugins/crm/includes/ZeroBSCRM.Permissions.php index 257895f9b512..8170c66a8505 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Permissions.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Permissions.php @@ -1,5 +1,5 @@ -has_cap( 'admin_zerobs_usr' ) ) { + $zeroBSCRM_isZBSUser = true; + } + if ( $cu->has_cap( 'zerobs_customer' ) ) { + $zeroBSCRM_isZBSUser = true; + } - #} Set a global var for this load, (sometimes multi-called) - global $zeroBSCRM_isZBSUser; + return $zeroBSCRM_isZBSUser; +} + // note this returns true if is any wp-admin based zbs user + // if want zbs customer roles too, use zeroBSCRM_permsIsZBSUser +function zeroBSCRM_permsIsZBSBackendUser() { - if (isset($zeroBSCRM_isZBSUser)) return $zeroBSCRM_isZBSUser; + #} Set a global var for this load, (sometimes multi-called) + global $zeroBSCRM_isZBSBackendUser; - #} ... else - $zeroBSCRM_isZBSUser = false; - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_usr')) $zeroBSCRM_isZBSUser = true; - if ($cu->has_cap('zerobs_customer')) $zeroBSCRM_isZBSUser = true; - - return $zeroBSCRM_isZBSUser; + if ( isset( $zeroBSCRM_isZBSBackendUser ) ) { + return $zeroBSCRM_isZBSBackendUser; } - // note this returns true if is any wp-admin based zbs user - // if want zbs customer roles too, use zeroBSCRM_permsIsZBSUser - function zeroBSCRM_permsIsZBSBackendUser(){ - #} Set a global var for this load, (sometimes multi-called) - global $zeroBSCRM_isZBSBackendUser; + #} ... else + $zeroBSCRM_isZBSBackendUser = false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_usr' ) ) { + $zeroBSCRM_isZBSBackendUser = true; + } - if (isset($zeroBSCRM_isZBSBackendUser)) return $zeroBSCRM_isZBSBackendUser; + return $zeroBSCRM_isZBSBackendUser; +} - #} ... else - $zeroBSCRM_isZBSBackendUser = false; - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_usr')) $zeroBSCRM_isZBSBackendUser = true; - - return $zeroBSCRM_isZBSBackendUser; - } - /* * Checks whether current user (or specified WP ID) is backend user, or wp admin - * + * * @param $wordpress_users_id - bool|int; if passed, will check this WordPress user ID rather than current user */ - function zeroBSCRM_permsIsZBSUserOrAdmin( $wordpress_user_id = false ) { +function zeroBSCRM_permsIsZBSUserOrAdmin( $wordpress_user_id = false ) { - // param passed? - if ( $wordpress_user_id == false ) { + // param passed? + if ( $wordpress_user_id == false ) { - // if using current wordpress user: - - // Maintain a global var for this load, (sometimes called multiple times) - // (Only for current user checks) - global $zeroBSCRM_isZBSBackendUser; - - // check if already checked - if ( isset( $zeroBSCRM_isZBSBackendUser ) ){ - return $zeroBSCRM_isZBSBackendUser; - } + // if using current WordPress user: - // else check: - $zeroBSCRM_isZBSBackendUser = false; - $user = wp_get_current_user(); + // Maintain a global var for this load, (sometimes called multiple times) + // (Only for current user checks) + global $zeroBSCRM_isZBSBackendUser; + // check if already checked + if ( isset( $zeroBSCRM_isZBSBackendUser ) ) { + return $zeroBSCRM_isZBSBackendUser; + } - } else { + // else check: + $zeroBSCRM_isZBSBackendUser = false; + $user = wp_get_current_user(); - // using passed user id + } else { - $user = get_userdata( $wordpress_user_id ); + // using passed user id - } + $user = get_userdata( $wordpress_user_id ); - // user isn't logged in, or the passed user ID no longer exists or is an invalid value - if ( !$user ) { - return false; - } + } - // crm user check - if ( $user->has_cap( 'admin_zerobs_usr' ) ){ - $zeroBSCRM_isZBSBackendUser = true; - return true; - } - - // admin check - if ( $user->has_cap( 'manage_options' ) ){ - return true; - } - + // user isn't logged in, or the passed user ID no longer exists or is an invalid value + if ( ! $user ) { return false; + } + // crm user check + if ( $user->has_cap( 'admin_zerobs_usr' ) ) { + $zeroBSCRM_isZBSBackendUser = true; + return true; } - function zeroBSCRM_isZBSAdmin(){ + // admin check + if ( $user->has_cap( 'manage_options' ) ) { + return true; + } - $cu = wp_get_current_user(); - //https://wordpress.stackexchange.com/questions/5047/how-to-check-if-a-user-is-in-a-specific-role - if (in_array( 'zerobs_admin', (array) $cu->roles )) return true; + return false; +} + +function zeroBSCRM_isZBSAdmin() { - return false; + $cu = wp_get_current_user(); + // https://wordpress.stackexchange.com/questions/5047/how-to-check-if-a-user-is-in-a-specific-role + if ( in_array( 'zerobs_admin', (array) $cu->roles ) ) { + return true; } - function zeroBSCRM_isWPAdmin(){ + return false; +} + +function zeroBSCRM_isWPAdmin() { - $cu = wp_get_current_user(); - - #} adm - if ($cu->has_cap('manage_options')) return true; + $cu = wp_get_current_user(); - return false; + #} adm + if ( $cu->has_cap( 'manage_options' ) ) { + return true; } - function zeroBSCRM_isZBSAdminOrAdmin(){ + return false; +} - $cu = wp_get_current_user(); - //https://wordpress.stackexchange.com/questions/5047/how-to-check-if-a-user-is-in-a-specific-role - if (in_array( 'zerobs_admin', (array) $cu->roles )) return true; +function zeroBSCRM_isZBSAdminOrAdmin() { - #} or adm - if ($cu->has_cap('manage_options')) return true; + $cu = wp_get_current_user(); + // https://wordpress.stackexchange.com/questions/5047/how-to-check-if-a-user-is-in-a-specific-role + if ( in_array( 'zerobs_admin', (array) $cu->roles ) ) { + return true; + } - return false; + #} or adm + if ( $cu->has_cap( 'manage_options' ) ) { + return true; } - function zeroBSCRM_wooCommerceRemoveBlock(){ - #} Add Filter for WooCommerce - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_usr')){ - add_filter( 'woocommerce_prevent_admin_access', '__return_false' ); - } + return false; +} + +function zeroBSCRM_wooCommerceRemoveBlock() { + #} Add Filter for WooCommerce + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_usr' ) ) { + add_filter( 'woocommerce_prevent_admin_access', '__return_false' ); } +} - function zeroBSCRM_getWordPressRoles(){ +function zeroBSCRM_getWordPressRoles() { - global $wp_roles; + global $wp_roles; - $all_roles = $wp_roles->roles; + $all_roles = $wp_roles->roles; - return $all_roles; - - } + return $all_roles; +} // return current user capabilities - function zeroBSCRM_getCurrentUserCaps(){ +function zeroBSCRM_getCurrentUserCaps() { - $data = get_userdata( get_current_user_id() ); + $data = get_userdata( get_current_user_id() ); - if ( is_object( $data) ) { - return array_keys($data->allcaps); - } - - return array(); + if ( is_object( $data ) ) { + return array_keys( $data->allcaps ); } + return array(); +} + /** * Determine if the current user is allowed to manage contacts. * @@ -630,316 +643,342 @@ function zeroBSCRM_permsCustomers() { return jpcrm_can_user_manage_contacts( $current_user ) === true; } - function zeroBSCRM_permsSendEmailContacts(){ +function zeroBSCRM_permsSendEmailContacts() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_sendemails_contacts')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_sendemails_contacts' ) ) { + return true; } - - function zeroBSCRM_permsViewCustomers(){ + return false; +} - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_view_customers')) return true; - return false; +function zeroBSCRM_permsViewCustomers() { + + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_view_customers' ) ) { + return true; } - function zeroBSCRM_permsCustomersTags(){ + return false; +} +function zeroBSCRM_permsCustomersTags() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_customers_tags')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_customers_tags' ) ) { + return true; } - function zeroBSCRM_permsQuotes(){ + return false; +} +function zeroBSCRM_permsQuotes() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_quotes')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_quotes' ) ) { + return true; } - function zeroBSCRM_permsViewQuotes(){ + return false; +} +function zeroBSCRM_permsViewQuotes() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_view_quotes')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_view_quotes' ) ) { + return true; } - function zeroBSCRM_permsInvoices(){ + return false; +} +function zeroBSCRM_permsInvoices() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_invoices')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_invoices' ) ) { + return true; } - function zeroBSCRM_permsViewInvoices(){ + return false; +} +function zeroBSCRM_permsViewInvoices() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_view_invoices')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_view_invoices' ) ) { + return true; } - function zeroBSCRM_permsTransactions(){ + return false; +} +function zeroBSCRM_permsTransactions() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_transactions')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_transactions' ) ) { + return true; } - function zeroBSCRM_permsViewTransactions(){ + return false; +} +function zeroBSCRM_permsViewTransactions() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_view_transactions')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_view_transactions' ) ) { + return true; } - function zeroBSCRM_permsMailCampaigns(){ + return false; +} +function zeroBSCRM_permsMailCampaigns() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_mailcampaigns')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_mailcampaigns' ) ) { + return true; } - function zeroBSCRM_permsForms(){ + return false; +} +function zeroBSCRM_permsForms() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_forms')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_forms' ) ) { + return true; } + return false; +} - function zeroBSCRM_perms_tasks(){ +function zeroBSCRM_perms_tasks() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_events')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_events' ) ) { + return true; } - function zeroBSCRM_permsNotify(){ + return false; +} +function zeroBSCRM_permsNotify() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_notifications')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_notifications' ) ) { + return true; } + return false; +} // NEEDS it's own cap when we get granular. - function zeroBSCRM_permsExport(){ +function zeroBSCRM_permsExport() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_customers')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_customers' ) ) { + return true; } + return false; +} // LOGS - // can add/edit logs - function zeroBSCRM_permsLogsAddEdit(){ +function zeroBSCRM_permsLogsAddEdit() { - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_logs_addedit')) return true; - return false; - } + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_logs_addedit' ) ) { + return true; + } + return false; +} // can delete logs - function zeroBSCRM_permsLogsDelete(){ - - $cu = wp_get_current_user(); - if ($cu->has_cap('admin_zerobs_logs_delete')) return true; - return false; - } - +function zeroBSCRM_permsLogsDelete() { + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'admin_zerobs_logs_delete' ) ) { + return true; + } + return false; +} - function zeroBSCRM_permsClient(){ //using Client to not confuse with Customer and Customer Manager +function zeroBSCRM_permsClient() { + // using Client to not confuse with Customer and Customer Manager - $cu = wp_get_current_user(); - if ($cu->has_cap('zerobs_customer')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'zerobs_customer' ) ) { + return true; } - function zeroBSCRM_permsWPEditPosts(){ + return false; +} +function zeroBSCRM_permsWPEditPosts() { - $cu = wp_get_current_user(); - if ($cu->has_cap('edit_posts')) return true; - return false; + $cu = wp_get_current_user(); + if ( $cu->has_cap( 'edit_posts' ) ) { + return true; } + return false; +} - function zeroBS_getPossibleCustomerOwners(){ return zeroBS_getPossibleOwners(array('zerobs_admin','zerobs_customermgr')); } - function zeroBS_getPossibleCompanyOwners(){ return zeroBS_getPossibleOwners(array('zerobs_admin','zerobs_customermgr')); } - function zeroBS_getPossibleQuoteOwners(){ return zeroBS_getPossibleOwners(array('zerobs_admin','zerobs_customermgr')); } - function zeroBS_getPossibleInvoiceOwners(){ return zeroBS_getPossibleOwners(array('zerobs_admin','zerobs_customermgr')); } - function zeroBS_getPossibleTransactionOwners(){ return zeroBS_getPossibleOwners(array('zerobs_admin','zerobs_customermgr')); } - function zeroBS_getPossibleTaskOwners(){ return zeroBS_getPossibleOwners(array('zerobs_admin','admin_zerobs_events')); } - - - // added this because Multi-site doesn't reliably +function zeroBS_getPossibleCustomerOwners() { + return zeroBS_getPossibleOwners( array( 'zerobs_admin', 'zerobs_customermgr' ) ); } +function zeroBS_getPossibleCompanyOwners() { + return zeroBS_getPossibleOwners( array( 'zerobs_admin', 'zerobs_customermgr' ) ); } +function zeroBS_getPossibleQuoteOwners() { + return zeroBS_getPossibleOwners( array( 'zerobs_admin', 'zerobs_customermgr' ) ); } +function zeroBS_getPossibleInvoiceOwners() { + return zeroBS_getPossibleOwners( array( 'zerobs_admin', 'zerobs_customermgr' ) ); } +function zeroBS_getPossibleTransactionOwners() { + return zeroBS_getPossibleOwners( array( 'zerobs_admin', 'zerobs_customermgr' ) ); } +function zeroBS_getPossibleTaskOwners() { + return zeroBS_getPossibleOwners( array( 'zerobs_admin', 'admin_zerobs_events' ) ); } + + // added this because Multi-site doesn't reliably // return on current_user_can('zerobs_customer') // https://wordpress.stackexchange.com/questions/5047/how-to-check-if-a-user-is-in-a-specific-role - function zeroBSCRM_isRole($role=''){ - - $user = wp_get_current_user(); - if ( in_array( $role, (array) $user->roles ) ) { - return true; - } - - return false; +function zeroBSCRM_isRole( $role = '' ) { + $user = wp_get_current_user(); + if ( in_array( $role, (array) $user->roles ) ) { + return true; } + return false; +} + /** * Checks a user object (or current user if false passed) * has roles in first array, and none of the roles in second array **/ - function jpcrm_role_check( $user_object = false, $has_roles = array(), $hasnt_roles = array(), $only_these_roles = array() ){ +function jpcrm_role_check( $user_object = false, $has_roles = array(), $hasnt_roles = array(), $only_these_roles = array() ) { - // load current user if not passed - if ( !$user_object ){ - - $user_object = wp_get_current_user(); - - } + // load current user if not passed + if ( ! $user_object ) { - // got object? - if ( !$user_object ){ + $user_object = wp_get_current_user(); - return false; + } - } + // got object? + if ( ! $user_object ) { - // verify has_roles - if ( count( $has_roles ) > 0 ){ + return false; - foreach ( $has_roles as $role ){ + } - if ( !in_array( $role, $user_object->roles ) ) { + // verify has_roles + if ( count( $has_roles ) > 0 ) { - return false; + foreach ( $has_roles as $role ) { - } + if ( ! in_array( $role, $user_object->roles ) ) { - } + return false; + } } + } - // verify hasnt_roles - if ( count( $hasnt_roles ) > 0 ){ - - foreach ( $hasnt_roles as $role ){ - - if ( in_array( $role, $user_object->roles ) ) { + // verify hasnt_roles + if ( count( $hasnt_roles ) > 0 ) { - return false; + foreach ( $hasnt_roles as $role ) { - } + if ( in_array( $role, $user_object->roles ) ) { - } + return false; + } } + } - // verify only_roles - if ( count( $only_these_roles ) > 0 ){ - - $role_match_count = 0; - - foreach ( $user_object->roles as $role ){ - - if ( !in_array( $role, $only_these_roles ) ) { - - return false; - - } else { + // verify only_roles + if ( count( $only_these_roles ) > 0 ) { - $role_match_count++; + $role_match_count = 0; - } + foreach ( $user_object->roles as $role ) { - } + if ( ! in_array( $role, $only_these_roles ) ) { - if ( $role_match_count != count( $only_these_roles ) ){ + return false; - return false; + } else { - } + ++$role_match_count; + } } + if ( $role_match_count != count( $only_these_roles ) ) { - return true; + return false; + } } + return true; +} - function zeroBS_getPossibleOwners($permsReq='',$simplify=false){ - - // https://codex.wordpress.org/Function_Reference/get_users - /* possible args.. - $args = array( - 'blog_id' => $GLOBALS['blog_id'], - 'role' => '', - 'role__in' => array('administrator','zerobs_admin','zerobs_customermgr','zerobs_quotemgr','zerobs_invoicemgr','zerobs_transactionmgr',''), - 'role__not_in' => array(), - 'meta_key' => '', - 'meta_value' => '', - 'meta_compare' => '', - 'meta_query' => array(), - 'date_query' => array(), - 'include' => array(), - 'exclude' => array(), - 'orderby' => 'login', - 'order' => 'ASC', - 'offset' => '', - 'search' => '', - 'number' => '', - 'count_total' => false, - 'fields' => 'all', - 'who' => '', - ); - - */ - - - if (empty($permsReq) || !in_array($permsReq, array('zerobs_admin','zerobs_customermgr','zerobs_quotemgr','zerobs_invoicemgr','zerobs_transactionmgr'))){ +function zeroBS_getPossibleOwners( $permsReq = '', $simplify = false ) { - // all zbs users + admin - $args = array('role__in' => array('administrator','zerobs_admin','zerobs_customermgr','zerobs_quotemgr','zerobs_invoicemgr','zerobs_transactionmgr')); + // https://codex.wordpress.org/Function_Reference/get_users + /* + possible args.. + $args = array( + 'blog_id' => $GLOBALS['blog_id'], + 'role' => '', + 'role__in' => array('administrator','zerobs_admin','zerobs_customermgr','zerobs_quotemgr','zerobs_invoicemgr','zerobs_transactionmgr',''), + 'role__not_in' => array(), + 'meta_key' => '', + 'meta_value' => '', + 'meta_compare' => '', + 'meta_query' => array(), + 'date_query' => array(), + 'include' => array(), + 'exclude' => array(), + 'orderby' => 'login', + 'order' => 'ASC', + 'offset' => '', + 'search' => '', + 'number' => '', + 'count_total' => false, + 'fields' => 'all', + 'who' => '', + ); - } else { + */ - // specific roles :) (+- admin?) - $args = array('role__in' => array('administrator',$permsReq)); + if ( empty( $permsReq ) || ! in_array( $permsReq, array( 'zerobs_admin', 'zerobs_customermgr', 'zerobs_quotemgr', 'zerobs_invoicemgr', 'zerobs_transactionmgr' ) ) ) { + // all zbs users + admin + $args = array( 'role__in' => array( 'administrator', 'zerobs_admin', 'zerobs_customermgr', 'zerobs_quotemgr', 'zerobs_invoicemgr', 'zerobs_transactionmgr' ) ); - } + } else { - $users = get_users( $args ); + // specific roles :) (+- admin?) + $args = array( 'role__in' => array( 'administrator', $permsReq ) ); + } - // this is used by inline editing on list view, be careful if editing - if ($simplify){ + $users = get_users( $args ); - if (is_array($users)){ + // this is used by inline editing on list view, be careful if editing + if ( $simplify ) { - $ret = array(); + if ( is_array( $users ) ) { - foreach ($users as $u){ + $ret = array(); - $ret[] = array( + foreach ( $users as $u ) { - 'id' => $u->ID, - 'name' => $u->data->display_name, - 'email' => $u->data->user_email + $ret[] = array( - ); - } + 'id' => $u->ID, + 'name' => $u->data->display_name, + 'email' => $u->data->user_email, - $users = $ret; + ); } + $users = $ret; } - - return $users; - } -/* ====================================================== - / Role Helpers - ====================================================== */ + + return $users; +} +/* +====================================================== + / Role Helpers + ====================================================== */ /** * Checks whether a WP user has permissions to view an object - * + * * @param \WP_User $wp_user - WP user object. * @param int $obj_id - Object ID. * @param int $obj_type_id - Object type ID. - * - * @return bool indicating whether the WP user can view the current object + * + * @return bool indicating whether the WP user can view the current object */ function jpcrm_can_wp_user_view_object( $wp_user, $obj_id, $obj_type_id ) { @@ -982,95 +1021,93 @@ function jpcrm_can_wp_user_view_object( $wp_user, $obj_id, $obj_type_id ) { return false; } - // grant access if user has full permissions to view object type - if ( - $obj_type_id == ZBS_TYPE_QUOTE && $is_quote_admin - || $obj_type_id == ZBS_TYPE_INVOICE && $is_invoice_admin - ) { - return true; - } - - // object is not assigned - if ( !$assigned_contact_id ) { - return false; - } - - // verify current user is assigned user - $contact_id = zeroBS_getCustomerIDWithEmail( $wp_user->user_email ); - if ( $assigned_contact_id != $contact_id ) { - return false; - } - - // passed all checks, so go for liftoff - return true; + // grant access if user has full permissions to view object type + if ( + $obj_type_id == ZBS_TYPE_QUOTE && $is_quote_admin + || $obj_type_id == ZBS_TYPE_INVOICE && $is_invoice_admin + ) { + return true; + } + + // object is not assigned + if ( ! $assigned_contact_id ) { + return false; + } + + // verify current user is assigned user + $contact_id = zeroBS_getCustomerIDWithEmail( $wp_user->user_email ); + if ( $assigned_contact_id != $contact_id ) { + return false; + } + + // passed all checks, so go for liftoff + return true; } /** * Pass-thru helper function to get current user for use with jpcrm_can_wp_user_view_object() * Particularly useful for client portal functions. - * + * * @param int $obj_id * @param int $obj_type_id - * - * @return bool indicating whether the current user can view the current object + * + * @return bool indicating whether the current user can view the current object */ function jpcrm_can_current_wp_user_view_object( $obj_id, $obj_type_id ) { - $current_wp_user = wp_get_current_user(); - return jpcrm_can_wp_user_view_object( $current_wp_user, $obj_id, $obj_type_id ); + $current_wp_user = wp_get_current_user(); + return jpcrm_can_wp_user_view_object( $current_wp_user, $obj_id, $obj_type_id ); } - /** * Determines if client portal access is allowed via easy-access hashes. - * + * * @param int $obj_type_id - * + * * @return bool */ function jpcrm_can_access_portal_via_hash( $obj_type_id ) { - // easy access is disabled - if ( zeroBSCRM_getSetting( 'easyaccesslinks' ) != 1 ) { - return false; - } - - $security_request_name = jpcrm_get_easy_access_security_request_name_by_obj_type( $obj_type_id ); + // easy access is disabled + if ( zeroBSCRM_getSetting( 'easyaccesslinks' ) != 1 ) { + return false; + } - // unsupported object type - if ( !$security_request_name ) { - return false; - } + $security_request_name = jpcrm_get_easy_access_security_request_name_by_obj_type( $obj_type_id ); - // fail if already blocked (this is a nefarious user or bot) - if ( zeroBSCRM_security_blockRequest( $security_request_name ) ) { - return false; - } - // access via hash is allowed - return true; + // unsupported object type + if ( ! $security_request_name ) { + return false; + } + // fail if already blocked (this is a nefarious user or bot) + if ( zeroBSCRM_security_blockRequest( $security_request_name ) ) { + return false; + } + // access via hash is allowed + return true; } /** * Returns security request name by object type. - * + * * @param int $obj_type_id - * + * * @return string|bool request name or false if no match */ function jpcrm_get_easy_access_security_request_name_by_obj_type( $obj_type_id ) { - switch ( $obj_type_id ) { - case ZBS_TYPE_INVOICE: - $security_request_name = 'inveasy'; - break; - case ZBS_TYPE_QUOTE: - $security_request_name = 'quoeasy'; - break; - default: - $security_request_name = false; - } - - return $security_request_name; + switch ( $obj_type_id ) { + case ZBS_TYPE_INVOICE: + $security_request_name = 'inveasy'; + break; + case ZBS_TYPE_QUOTE: + $security_request_name = 'quoeasy'; + break; + default: + $security_request_name = false; + } + + return $security_request_name; } // show an error if bad permissions @@ -1078,7 +1115,7 @@ function jpcrm_perms_error() { echo zeroBSCRM_UI2_messageHTML( 'warning', __( 'Access Denied', 'zero-bs-crm' ), - __('You do not have permission to access this page.', 'zero-bs-crm' ), + __( 'You do not have permission to access this page.', 'zero-bs-crm' ), 'disabled warning sign', 'bad_perms' ); diff --git a/projects/plugins/crm/includes/ZeroBSCRM.PluginUpdates.php b/projects/plugins/crm/includes/ZeroBSCRM.PluginUpdates.php index 67d2e720fa14..45d4c0dfb57c 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.PluginUpdates.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.PluginUpdates.php @@ -1,64 +1,62 @@ -api_url = trailingslashit( $_api_url ); - $this->api_ver = untrailingslashit( $_api_ver ); // wh: not used as of this check? 17/8/18 - + $this->api_url = trailingslashit( $_api_url ); + $this->api_ver = untrailingslashit( $_api_ver ); // wh: not used as of this check? 17/8/18 + if ( is_array( $_api_data ) ) { // Prevent warning if it's null - $this->api_data = $_api_data; - $this->version = $_api_data['version']; + $this->api_data = $_api_data; + $this->version = $_api_data['version']; $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false; } // Set up hooks. $this->init(); } - /** - * Set up WordPress filters to hook into WP's update process. + * Set up WordPress filters to hook into WP's update process. * - pre_set_transient is the info on whether it needs updating * - plugins_api is when the 'view version [x.x] details' is clicked. */ @@ -69,26 +67,26 @@ public function init() { // can also use this, but untested: add_filter( 'site_transient_update_plugins', array( $this, 'check_update' ) ); // Set our own get_info call - add_filter( 'plugins_api', array( $this, 'get_info' ),10,3); + add_filter( 'plugins_api', array( $this, 'get_info' ), 10, 3 ); - // this 'renames' the source + // this 'renames' the source // fixes a WP bug where wp renames zero-bs-extension-password-manager to zero-bs-extension-password-manager-KGBdBz // (removes trailing group) // not req: add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 100, 4); add_filter( 'upgrader_source_selection', array( $this, 'maybe_adjust_source_dir' ), 1, 4 ); - } - /* =============================================================================================== + /* + =============================================================================================== ===================================== / init functions ========================================== - =============================================================================================== */ - + =============================================================================================== + */ - - /* =============================================================================================== + /* + =============================================================================================== ==================================== main call functions ======================================== - =============================================================================================== */ - + =============================================================================================== + */ public function check_update( $transient ) { @@ -96,21 +94,21 @@ public function check_update( $transient ) { global $zbs; // define - $zbs_plugins = array(); + $zbs_plugins = array(); $zbs_check_update_start = time(); - $installedExts = 0; + $installedExts = 0; // retrieves all active/all WP plugins installed (not just ours) // Further gets other configs of same... - $active_plugins = get_option('active_plugins'); - $zbs_active_plugins = zeroBSCRM_activePluginListSimple(); + $active_plugins = get_option( 'active_plugins' ); + $zbs_active_plugins = zeroBSCRM_activePluginListSimple(); $zbs_all_plugins_and_ver = zeroBSCRM_allPluginListSimple(); - $zbs_extensions_on_site = zeroBSCRM_installedProExt(); - $active_core_modules = jpcrm_core_modules_installed(); - $installedExts = zeroBSCRM_extensionsInstalledCount(); + $zbs_extensions_on_site = zeroBSCRM_installedProExt(); + $active_core_modules = jpcrm_core_modules_installed(); + $installedExts = zeroBSCRM_extensionsInstalledCount(); // 7/1/19 - needs to do if key entered, regardless of if ext, because some peeps enter it before adding extensions - if( $installedExts > 0 || $this->get_license_key() !== false ) { + if ( $installedExts > 0 || $this->get_license_key() !== false ) { // retrieve license key info (later overwritten if updating) $key_info = $zbs->settings->get( 'license_key' ); @@ -124,15 +122,15 @@ public function check_update( $transient ) { 'active-extensions' => $active_plugins, 'telemetry-active' => $zbs_active_plugins, 'telemetry-all' => $zbs_all_plugins_and_ver, - 'core-modules' => $active_core_modules + 'core-modules' => $active_core_modules, ) - ); //, 'license'=>$lk + ); // , 'license'=>$lk // if got response - if ( ! is_wp_error( $response ) ) { + if ( ! is_wp_error( $response ) ) { - // check presence of license_key_valid - // ... this catches the faulty/empty/devmode ones + // check presence of license_key_valid + // ... this catches the faulty/empty/devmode ones if ( isset( $response['license_key_valid'] ) && ( $response['license_key_valid'] == 'false' || $response['license_key_valid'] == 'empty' || $response['license_key_valid'] == '' || $response['license_key_valid'] == 'expired' ) ) { // is it dev mode? @@ -150,25 +148,25 @@ public function check_update( $transient ) { } // if this is saying false, then send a notification IF we haven't nagged for 5 days - if ( !get_transient( 'zbs-nag-license-key-now' ) ) { + if ( ! get_transient( 'zbs-nag-license-key-now' ) ) { // generate nag - $link = admin_url( 'admin.php?page=zerobscrm-plugin-settings&tab=license' ); - $parameters = __( 'Your License Key is incorrect.', 'zero-bs-crm' ) . ' ' . __( 'Please enter your license key here.', 'zero-bs-crm') . ''; - $reference = time(); - $cid = get_current_user_id(); + $link = admin_url( 'admin.php?page=zerobscrm-plugin-settings&tab=license' ); + $parameters = __( 'Your License Key is incorrect.', 'zero-bs-crm' ) . ' ' . __( 'Please enter your license key here.', 'zero-bs-crm' ) . ''; + $reference = time(); + $cid = get_current_user_id(); #NAG-ME-PLZ zeroBSCRM_notifyme_insert_notification( $cid, -999, -1, 'license.update.needed', $parameters, $reference ); set_transient( 'zbs-nag-license-key-now', 'nag', $this->nag_every ); - + } // / if set nag } // / if not dev mode - // Otherwise, this is a valid license key - // so next check if it's a rebranded one - } else if ( $response['license_key_valid'] == 'brand.template' ) { + // Otherwise, this is a valid license key + // so next check if it's a rebranded one + } elseif ( $response['license_key_valid'] == 'brand.template' ) { // set validity - no brand template $key_info['validity'] = ''; @@ -181,20 +179,20 @@ public function check_update( $transient ) { // if this is saying false, then send a notification IF we haven't nagged for 5 days // (rebrandr template needed) - if ( !get_transient( 'zbs-nag-license-key-now' ) ) { + if ( ! get_transient( 'zbs-nag-license-key-now' ) ) { // generate nag - $link = admin_url( 'admin.php?page=zerobscrm-plugin-settings&tab=license' ); - $parameters = __( 'Your License Key is not linked to a CRM Brand (Error #401)', 'zero-bs-crm') . ' ' . __( 'Please enter your license key here.', 'zero-bs-crm') . ''; - $reference = time(); - $cid = get_current_user_id(); + $link = admin_url( 'admin.php?page=zerobscrm-plugin-settings&tab=license' ); + $parameters = __( 'Your License Key is not linked to a CRM Brand (Error #401)', 'zero-bs-crm' ) . ' ' . __( 'Please enter your license key here.', 'zero-bs-crm' ) . ''; + $reference = time(); + $cid = get_current_user_id(); #NAG-ME-PLZ zeroBSCRM_notifyme_insert_notification( $cid, -999, -1, 'license.update.needed', $parameters, $reference ); set_transient( 'zbs-nag-license-key-now', 'nag', $this->nag_every ); } - // otherwise this is a legit key :) + // otherwise this is a legit key :) } else { // set validity @@ -205,7 +203,7 @@ public function check_update( $transient ) { $key_info['access'] = sanitize_text_field( $response['access'] ); } if ( isset( $response['expires'] ) ) { - $key_info['expires'] = (int)sanitize_text_field( $response['expires'] ); + $key_info['expires'] = (int) sanitize_text_field( $response['expires'] ); } // if this was the first time this api been used, it'll also send this back: @@ -216,7 +214,6 @@ public function check_update( $transient ) { $zbsLicenseClaimed = true; } - } // here we build a var containing the correct 'up to date versions' @@ -246,7 +243,7 @@ public function check_update( $transient ) { // Local Mods to dl obj - these are needed in get_info and all_info (here) $newSlug = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $e = false; + $e = false; if ( is_array( $pluginDetails ) && isset( $pluginDetails['path'] ) ) { $e = explode( '/', $pluginDetails['path'] ); } @@ -257,7 +254,7 @@ public function check_update( $transient ) { $newSlug = $extUpdateInfo['slug']; } - // this isn't needed once dl link fixed server side :) + // this isn't needed once dl link fixed server side :) // actually, is a fairly legit fix for now // ... MAKES SURE installs in same dir as current for that ext, even in rebranded $modifiedDLLink = false; @@ -279,27 +276,26 @@ public function check_update( $transient ) { $obj->package = $modifiedDLLink; // these errored on some rebrandr, so setting defaults - $obj->url = false; + $obj->url = false; // these errored on some rebrandr, so checking first to stop php notices if ( isset( $extUpdateInfo['url'] ) ) { $obj->url = $extUpdateInfo['url']; } if ( isset( $pluginDetails['path'] ) ) { - $transient->response[$pluginDetails['path']] = $obj; - } - else { + $transient->response[ $pluginDetails['path'] ] = $obj; + } else { $transient->response[] = $obj; } // generate nag // then we are adding the notification to "please update Jetpack CRM extension "X") - $parameters = sprintf( __( 'Please update %s from version %s to version %s.', 'zero-bs-crm' ), $pluginDetails['name'], $pluginDetails['ver'], $extUpdateInfo['version'] ); - $ref = $pluginDetails['ver'] . $extUpdateInfo['version']; + $parameters = sprintf( __( 'Please update %1$s from version %2$s to version %3$s.', 'zero-bs-crm' ), $pluginDetails['name'], $pluginDetails['ver'], $extUpdateInfo['version'] ); + $ref = $pluginDetails['ver'] . $extUpdateInfo['version']; #NAG-ME-PLZ $reference = $pluginDetails['key'] . str_replace( '.', '', $ref ); - $cid = get_current_user_id(); + $cid = get_current_user_id(); zeroBSCRM_notifyme_insert_notification( $cid, -999, -1, 'custom.extension.update.needed', $parameters, $reference ); // make note that something needs an update @@ -308,13 +304,11 @@ public function check_update( $transient ) { } // / end if ver is newer } // / end if key matches - + } // / end cycle through $official_ver } - } // / end cycle through $zbs_extensions_on_site - // This checks that this plugin_update is being called on a rebranded plugin // .. further, it then proceeds to check if the WL ver of CORE CRM needs updating // .. as that's not hosted on wp.org, it's a rebrand/remix :) @@ -344,7 +338,7 @@ public function check_update( $transient ) { // Local Mods to dl obj - these are needed in get_info and all_info (here) $newSlug = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $e = explode( '/', $core['path'] ); + $e = explode( '/', $core['path'] ); if ( is_array( $e ) ) { $newSlug = $e[0]; } @@ -352,7 +346,7 @@ public function check_update( $transient ) { $newSlug = $coreUpdateInfo['slug']; } - // this isn't needed once dl link fixed server side :) + // this isn't needed once dl link fixed server side :) // actually, is a fairly legit fix for now // ... MAKES SURE installs in same dir as current for that ext, even in rebranded $modifiedDLLink = $coreUpdateInfo['download_link']; @@ -374,12 +368,12 @@ public function check_update( $transient ) { // generate nag // then we are adding the notification to "please update Jetpack CRM extension "X") - $parameters = sprintf( __( 'Please update %s from version %s to version %s.', 'zero-bs-crm' ), $core['name'], $core['ver'], $coreUpdateInfo['version'] ); - $ref = $core['ver'] . $coreUpdateInfo['version']; - + $parameters = sprintf( __( 'Please update %1$s from version %2$s to version %3$s.', 'zero-bs-crm' ), $core['name'], $core['ver'], $coreUpdateInfo['version'] ); + $ref = $core['ver'] . $coreUpdateInfo['version']; + #NAG-ME-PLZ $reference = $core['key'] . str_replace( '.', '', $ref ); - $cid = get_current_user_id(); + $cid = get_current_user_id(); zeroBSCRM_notifyme_insert_notification( $cid, -999, -1, 'core.update.needed', $parameters, $reference ); // make note that something needs an update @@ -392,17 +386,17 @@ public function check_update( $transient ) { } // if is rebranded // If not all the Jetpack CRM extensions are updated. Fire off the warning shot. - if( !$extensions_all_updated ) { + if ( ! $extensions_all_updated ) { // 1+ ext needs update // Recently nagged? - if( !get_transient( 'zbs-nag-extension-update-now' ) ) { + if ( ! get_transient( 'zbs-nag-extension-update-now' ) ) { // generate nag $parameters = __( 'You are running extensions which are out of date and not supported. Please update to avoid any issues.', 'zero-bs-crm' ); - $reference = time(); - $cid = get_current_user_id(); + $reference = time(); + $cid = get_current_user_id(); #NAG-ME-PLZ zeroBSCRM_notifyme_insert_notification( $cid, -999, -1, 'general.extension.update.needed', $parameters, $reference ); @@ -421,7 +415,6 @@ public function check_update( $transient ) { $key_info['extensions_updated'] = true; } - } else { // There was a WP Error @@ -440,7 +433,7 @@ public function check_update( $transient ) { #} This fires when a user clicks "view version x.x.x information" next to an update in plugins.php or update-core.php // ... showing the info in the modal popup - public function get_info($obj, $action, $arg){ + public function get_info( $obj, $action, $arg ) { // is this an info req? & is slug set? if ( $action === 'plugin_information' && isset( $arg->slug ) ) { @@ -450,18 +443,24 @@ public function get_info($obj, $action, $arg){ // or is it core? if ( ! is_array( $possibleExtension ) ) { - $possibleExtension = $this->getCoreWLCRM( $arg->slug ); - } + $possibleExtension = $this->getCoreWLCRM( $arg->slug ); + } // if this is an array, it's either one of our ext or the core (or either rebranded) if ( is_array( $possibleExtension ) ) { // we'll need this: global $zbs; - + // do api request to get the info from api.jetpackcrm.com - $res = $this->api_request( 'ext_info', array( 'slug' => $arg->slug, 'key' => $possibleExtension['key'] ) ); - + $res = $this->api_request( + 'ext_info', + array( + 'slug' => $arg->slug, + 'key' => $possibleExtension['key'], + ) + ); + // is it a WP error? if ( ! is_wp_error( $res ) ) { @@ -471,17 +470,21 @@ public function get_info($obj, $action, $arg){ $newSlug = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $modifiedDLLink = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $e = explode('/',$possibleExtension['path']); - if (is_array($e)) $newSlug = $e[0]; - if (empty($newSlug)) $newSlug = $res['slug']; + $e = explode( '/', $possibleExtension['path'] ); + if ( is_array( $e ) ) { + $newSlug = $e[0]; + } + if ( empty( $newSlug ) ) { + $newSlug = $res['slug']; + } - if (isset($res['download_link']) && $res['download_link'] !== 'false' && !empty($newSlug)) { + if ( isset( $res['download_link'] ) && $res['download_link'] !== 'false' && ! empty( $newSlug ) ) { - // this isn't needed once dl link fixed server side :) + // this isn't needed once dl link fixed server side :) // actually, is a fairly legit fix for now // ... MAKES SURE installs in same dir as current for that ext, even in rebranded $modifiedDLLink = $res['download_link']; - $modifiedDLLink = str_replace('?','/'.$newSlug.'.zip?',$modifiedDLLink); + $modifiedDLLink = str_replace( '?', '/' . $newSlug . '.zip?', $modifiedDLLink ); } @@ -489,137 +492,142 @@ public function get_info($obj, $action, $arg){ // =========================== // Build 'update needed' obj ref - $obj = new stdClass(); - $obj->slug = $newSlug; - $obj->plugin_name = $res['slug']; - $obj->new_version = $res['version']; - $obj->requires = $res['requires']; - - // name - if (isset($res['name'])) - $obj->name = $res['name']; - elseif (isset($possibleExtension['name'])) - $obj->name = $possibleExtension['name']; - else - $obj->name = ''; - + $obj = new stdClass(); + $obj->slug = $newSlug; + $obj->plugin_name = $res['slug']; + $obj->new_version = $res['version']; + $obj->requires = $res['requires']; + + // name + if ( isset( $res['name'] ) ) { + $obj->name = $res['name']; + } elseif ( isset( $possibleExtension['name'] ) ) { + $obj->name = $possibleExtension['name']; + } else { + $obj->name = ''; + } + // tested to - if (isset($res['tested'])) - $obj->tested = $res['tested']; - else - // default to latest in core + if ( isset( $res['tested'] ) ) { + $obj->tested = $res['tested']; + } else { // default to latest in core $obj->tested = $zbs->wp_tested; + } // url - if (isset($res['url'])) - $obj->url = $res['url']; - else - // default to core - $obj->url = $zbs->urls['home']; - + if ( isset( $res['url'] ) ) { + $obj->url = $res['url']; + } else { // default to core + $obj->url = $zbs->urls['home']; + } + // mod link - if (isset($modifiedDLLink) && !empty($modifiedDLLink)){ - $obj->download_link = $modifiedDLLink; - $obj->package = $modifiedDLLink; - } + if ( isset( $modifiedDLLink ) && ! empty( $modifiedDLLink ) ) { + $obj->download_link = $modifiedDLLink; + $obj->package = $modifiedDLLink; + } - // html sections - if (isset($res['sections'])) - $obj->sections = $res['sections']; - else - // default + // html sections + if ( isset( $res['sections'] ) ) { + $obj->sections = $res['sections']; + } else { // default $obj->sections = array(); + } // optional - if (isset($res['banners'])) $obj->banners = $res['banners']; - if (isset($res['downloaded'])) $obj->downloaded = $res['downloaded']; - if (isset($res['last_updated'])) $obj->last_updated = $res['last_updated']; - - + if ( isset( $res['banners'] ) ) { + $obj->banners = $res['banners']; + } + if ( isset( $res['downloaded'] ) ) { + $obj->downloaded = $res['downloaded']; + } + if ( isset( $res['last_updated'] ) ) { + $obj->last_updated = $res['last_updated']; + } } // / end if ! wp error } // / end if is one of ours } // / end if slug set && is plugin_information - // return the singular update obj - return $obj; - + return $obj; } - - /* =============================================================================================== + /* + =============================================================================================== =================================== / main call functions ======================================== - =============================================================================================== */ - - + =============================================================================================== + */ - /* =============================================================================================== + /* + =============================================================================================== ===================================== helper functions ========================================== - =============================================================================================== */ + =============================================================================================== + */ // Retrieves license key, (if is one), from settings obj - public function get_license_key(){ + public function get_license_key() { global $zbs; - $settings = $zbs->settings->get('license_key'); - + $settings = $zbs->settings->get( 'license_key' ); + // checks if exists and it's not empty if ( ! empty( $settings['key'] ) ) { return $settings['key']; } return false; - } - public function isLicenseValid(){ - - // taken wholesale out of adminPages license key page. + public function isLicenseValid() { - $licenseKeyArr = zeroBSCRM_getSetting('license_key'); - // simplify following: - $licenseValid = false; if (isset($licenseKeyArr['validity'])) $licenseValid = ($licenseKeyArr['validity'] === 'true'); + // taken wholesale out of adminPages license key page. - return $licenseValid; + $licenseKeyArr = zeroBSCRM_getSetting( 'license_key' ); + // simplify following: + $licenseValid = false; + if ( isset( $licenseKeyArr['validity'] ) ) { + $licenseValid = ( $licenseKeyArr['validity'] === 'true' ); + } + return $licenseValid; } - /** * This is used to verify if is one of our extensions * >> only hook in if the slug is one of our plugins!! :) */ - public function isCRMExtension($slug=''){ + public function isCRMExtension( $slug = '' ) { // req. global $zbs; // if slug passed - if (!empty($slug)){ + if ( ! empty( $slug ) ) { // get latest list (or cache) - if (!is_array($this->installedExts)) $this->installedExts = zeroBSCRM_installedProExt(); + if ( ! is_array( $this->installedExts ) ) { + $this->installedExts = zeroBSCRM_installedProExt(); + } - // cycle through em - foreach ($this->installedExts as $extName => $extDeets){ + // cycle through em + foreach ( $this->installedExts as $extName => $extDeets ) { // debug echo 'checking '.$extDeets['slug'].' against '.$slug.'
'; // is slug in this arr? - if (is_array($extDeets) && isset($extDeets['slug']) && $extDeets['slug'] == $slug) return true; - + if ( is_array( $extDeets ) && isset( $extDeets['slug'] ) && $extDeets['slug'] == $slug ) { + return true; + } } - } return false; - } #} Retireve extension details array based on the plugin slug - public function getCRMExtension( $slug='' ) { + public function getCRMExtension( $slug = '' ) { global $zbs; @@ -628,8 +636,8 @@ public function getCRMExtension( $slug='' ) { // get latest list (or cache) if ( ! is_array( $this->installedExts ) ) { - $this->installedExts = zeroBSCRM_installedProExt(); - } + $this->installedExts = zeroBSCRM_installedProExt(); + } // cycle through each, check if matches foreach ( $this->installedExts as $extName => $extDeets ) { @@ -640,19 +648,15 @@ public function getCRMExtension( $slug='' ) { ) { // simple return. - $x = $extDeets; + $x = $extDeets; $x['shortname'] = $extName; return $x; } - } - - } // / if slug // no luck return false; - } #} Retireve rebranded core crm plugin details array based on the plugin slug @@ -660,53 +664,52 @@ public function getCoreWLCRM( $slug = '' ) { // req. global $zbs; - + // is this install rebranded, and is there a slug? if ( zeroBSCRM_isWL() && ! empty( $slug ) && $slug !== 'jetpack' ) { // get core ver $core = zeroBSCRM_installedWLCore(); - //echo 'core:';print_r($core); + // echo 'core:';print_r($core); // is core wl? - if (isset($core) && is_array($core) && isset($core['ver'])){ + if ( isset( $core ) && is_array( $core ) && isset( $core['ver'] ) ) { // is this it? - if ( + if ( // something else we changed, changed this. Use first part of path now, not slug. ( is_array( $core ) && isset( $core['path'] ) && str_starts_with( $core['path'], $slug ) ) ) { - $x = $core; - $x['shortname'] = $core['name']; - return $x; - } - + $x = $core; + $x['shortname'] = $core['name']; + return $x; + } } // / this is core & it has a ver - } // / is this install rebranded, and is there a slug? return false; - } - // Retrieves the latest info for ZBS extension list, or singular (if get_info) // 13/12/18 - this now caches, as is recalled for each plugin when getting all_info. - // cachcing = side-hack for v1.0 - public function api_request($action, $data){ + // cachcing = side-hack for v1.0 + public function api_request( $action, $data ) { - // req. + // req. global $zbs; // discern multisite, WL - $multisite = false; $wl = false; + $multisite = false; + $wl = false; $multisite = is_multisite(); - if ($multisite == ''){ + if ( $multisite == '' ) { $multisite = false; - } if (zeroBSCRM_isWL()) $wl = true; + } if ( zeroBSCRM_isWL() ) { + $wl = true; + } // build request data package $api_params = array( @@ -730,62 +733,69 @@ public function api_request($action, $data){ // got cache? (we don't cache ext_info) global $zbsExtUpdateCache; - if ($action !== 'ext_info' && isset($zbsExtUpdateCache) && is_array($zbsExtUpdateCache)){ - + if ( $action !== 'ext_info' && isset( $zbsExtUpdateCache ) && is_array( $zbsExtUpdateCache ) ) { + return $zbsExtUpdateCache; - + } else { - // note, if we have recurring failures in this license key retrieve, it's likely that their is an SSL issue // + // note, if we have recurring failures in this license key retrieve, it's likely that their is an SSL issue // // https://wordpress.stackexchange.com/questions/167898/is-it-safe-to-use-sslverify-true-for-with-wp-remote-get-wp-remote-post - $licensingAttempts = $zbs->DAL->setting('licensingcount',0); + $licensingAttempts = $zbs->DAL->setting( 'licensingcount', 0 ); // check for setting - $hasHitError = $zbs->DAL->setting('licensingerror',false); if (is_array($hasHitError)) $hasHitError = true; + $hasHitError = $zbs->DAL->setting( 'licensingerror', false ); + if ( is_array( $hasHitError ) ) { + $hasHitError = true; + } // if 1 + no success, turn this off for third - $sslIgnore = false; if ($licensingAttempts > 0 && !$this->isLicenseValid() && $hasHitError) $sslIgnore = true; - if ($sslIgnore){ + $sslIgnore = false; + if ( $licensingAttempts > 0 && ! $this->isLicenseValid() && $hasHitError ) { + $sslIgnore = true; + } + if ( $sslIgnore ) { add_filter( 'https_ssl_verify', '__return_false' ); } // run the req. - $responseFull = wp_remote_post( $this->api_url, array( - 'method' => 'POST', - 'timeout' => 60, - 'redirection' => 5, - 'httpversion' => '1.0', - 'blocking' => true, - 'headers' => array(), - 'body' => $api_params, - 'cookies' => array() - ) + $responseFull = wp_remote_post( + $this->api_url, + array( + 'method' => 'POST', + 'timeout' => 60, + 'redirection' => 5, + 'httpversion' => '1.0', + 'blocking' => true, + 'headers' => array(), + 'body' => $api_params, + 'cookies' => array(), + ) ); // remove filter if set - if ($sslIgnore){ + if ( $sslIgnore ) { remove_filter( 'https_ssl_verify', '__return_false' ); } // up count. - $zbs->DAL->updateSetting('licensingcount',($licensingAttempts+1)); + $zbs->DAL->updateSetting( 'licensingcount', ( $licensingAttempts + 1 ) ); // hmmm - was wary of only allowing 200, but probs makes more sense than this? - $unacceptableHTTPCodes = array(500,443); - $httpCode = wp_remote_retrieve_response_code($responseFull); + $unacceptableHTTPCodes = array( 500, 443 ); + $httpCode = wp_remote_retrieve_response_code( $responseFull ); // got wp err? - if ( ! is_wp_error( $responseFull ) && !in_array($httpCode,$unacceptableHTTPCodes)) { + if ( ! is_wp_error( $responseFull ) && ! in_array( $httpCode, $unacceptableHTTPCodes ) ) { // decode - $response = json_decode( $responseFull['body'],true ); + $response = json_decode( $responseFull['body'], true ); // set cache $zbsExtUpdateCache = $response; // clear any err - $zbs->DAL->updateSetting('licensingerror',false); - + $zbs->DAL->updateSetting( 'licensingerror', false ); // return return $response; @@ -793,37 +803,50 @@ public function api_request($action, $data){ } else { // wp err - if (is_wp_error( $responseFull )){ + if ( is_wp_error( $responseFull ) ) { // log the err - $zbs->DAL->updateSetting('licensingerror',array('time'=>time(), 'err' => $responseFull->get_error_message())); + $zbs->DAL->updateSetting( + 'licensingerror', + array( + 'time' => time(), + 'err' => $responseFull->get_error_message(), + ) + ); } - // http err - if (in_array($httpCode,$unacceptableHTTPCodes)) { + // http err + if ( in_array( $httpCode, $unacceptableHTTPCodes ) ) { // log the err - $msg = ''; if (is_array($responseFull) && isset($responseFull['message'])) $msg = $responseFull['message']; - $zbs->DAL->updateSetting('licensingerror',array('time'=>time(), 'err' => 'Error:'.$httpCode.' '.$msg)); + $msg = ''; + if ( is_array( $responseFull ) && isset( $responseFull['message'] ) ) { + $msg = $responseFull['message']; + } + $zbs->DAL->updateSetting( + 'licensingerror', + array( + 'time' => time(), + 'err' => 'Error:' . $httpCode . ' ' . $msg, + ) + ); } - } } return false; - } - - /* This is a WH hack using + /* + This is a WH hack using .... https://github.com/CherryFramework/cherry-plugin-wizard/blob/master/includes/class-cherry-plugin-wizard-plugin-upgrader.php#L71 ... as a base ... which shoves itself in the middle of all plugin installs/upgrades ... IF it finds that the plugin being updated is one of OURS, it'll intercede and change: - ... zero-bs-extension-password-manager-KGBdBz - ... to + ... zero-bs-extension-password-manager-KGBdBz + ... to ... zero-bs-extension-password-manager Useful: @@ -846,278 +869,298 @@ public function api_request($action, $data){ * @param \WP_Upgrader $upgrader Instance of the upgrader which installs the plugin. * @return string $source */ - public function maybe_adjust_source_dir( $source, $remote_source, $upgrader, $extraArgs ) { - - // is this one of our plugins that's being updated? (will be called by all) - $ours = false; $pluginPath = false; - if (isset($extraArgs) && isset($extraArgs['plugin']) && !empty($extraArgs['plugin'])) $pluginPath = $extraArgs['plugin']; - - // normal ext + rebranded ext test - if ($pluginPath !== false){ - $ourExts = zeroBSCRM_installedProExt(); - if (is_array($ourExts)) foreach ($ourExts as $x => $ext) if ($ext['path'] == $pluginPath) $ours = true; - } + public function maybe_adjust_source_dir( $source, $remote_source, $upgrader, $extraArgs ) { - // wl(rebranded) core test - if ($pluginPath !== false && zeroBSCRM_isWL()){ + // is this one of our plugins that's being updated? (will be called by all) + $ours = false; + $pluginPath = false; + if ( isset( $extraArgs ) && isset( $extraArgs['plugin'] ) && ! empty( $extraArgs['plugin'] ) ) { + $pluginPath = $extraArgs['plugin']; + } - // core check - $core = zeroBSCRM_installedWLCore(); + // normal ext + rebranded ext test + if ( $pluginPath !== false ) { + $ourExts = zeroBSCRM_installedProExt(); + if ( is_array( $ourExts ) ) { + foreach ( $ourExts as $x => $ext ) { + if ( $ext['path'] == $pluginPath ) { + $ours = true; + } + } + } + } - // if wl core is installed - if (isset($core) && is_array($core) && isset($core['ver'])){ + // wl(rebranded) core test + if ( $pluginPath !== false && zeroBSCRM_isWL() ) { - if ($core['path'] == $pluginPath) $ours = true; + // core check + $core = zeroBSCRM_installedWLCore(); - } + // if wl core is installed + if ( isset( $core ) && is_array( $core ) && isset( $core['ver'] ) ) { + if ( $core['path'] == $pluginPath ) { + $ours = true; } + } + } // if not ours, just return $source for now // otherwise use ORIGINAL plugin dir :) // https://core.trac.wordpress.org/browser/tags/5.0/src/wp-admin/includes/class-wp-upgrader.php#L502 - if (!$ours) return $source; + if ( ! $ours ) { + return $source; + } - // req. - global $wp_filesystem; if (! is_object( $wp_filesystem ) ) { return $source; } + // req. + global $wp_filesystem; + if ( ! is_object( $wp_filesystem ) ) { + return $source; } // check from path - $from_path = untrailingslashit( $source ); + $from_path = untrailingslashit( $source ); $desired_slug = isset( $extraArgs['plugin'] ) ? $extraArgs['plugin'] : false; - if (!empty($desired_slug)) { - $e = explode('/',$desired_slug); - if (is_array($e)) $desired_slug = $e[0]; - if (empty($desired_slug)) return $source; + if ( ! empty( $desired_slug ) ) { + $e = explode( '/', $desired_slug ); + if ( is_array( $e ) ) { + $desired_slug = $e[0]; } - if ( ! $desired_slug ) { + if ( empty( $desired_slug ) ) { return $source; } + } + if ( ! $desired_slug ) { + return $source; + } // holder dir $to_path = untrailingslashit( $source ); - - // remove working dir + + // remove working dir // ?? not req. // attempt to build a 'proper' to_path - if (!empty($to_path)) { - $to_path = substr($to_path,0,strrpos($to_path,'/')); - $to_path .= '/'.$desired_slug; - } + if ( ! empty( $to_path ) ) { + $to_path = substr( $to_path, 0, strrpos( $to_path, '/' ) ); + $to_path .= '/' . $desired_slug; + } // if checks out... - if ( ! empty( $to_path ) && $to_path !== $from_path ) { + if ( ! empty( $to_path ) && $to_path !== $from_path ) { - if ( true === $wp_filesystem->move( $from_path, $to_path ) ) { - return trailingslashit( $to_path ); - } else { - return new WP_Error( - 'rename_failed', - esc_html__( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.', 'zero-bs-crm' ) . ' ' . esc_html__( 'Please contact the plugin provider and ask them to package their plugin according to the WordPress guidelines.', 'zero-bs-crm' ), - array( 'found' => $to_path, 'expected' => $desired_slug ) - ); - } - } elseif ( empty( $to_path ) ) { + if ( true === $wp_filesystem->move( $from_path, $to_path ) ) { + return trailingslashit( $to_path ); + } else { return new WP_Error( - 'packaged_wrong', - esc_html__( 'The remote plugin package consists of more than one file, but the files are not packaged in a folder.', 'zero-bs-crm' ) . ' ' . esc_html__( 'Please contact the plugin provider and ask them to package their plugin according to the WordPress guidelines.', 'zero-bs-crm' ), - array( 'found' => $to_path, 'expected' => $desired_slug ) + 'rename_failed', + esc_html__( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.', 'zero-bs-crm' ) . ' ' . esc_html__( 'Please contact the plugin provider and ask them to package their plugin according to the WordPress guidelines.', 'zero-bs-crm' ), + array( + 'found' => $to_path, + 'expected' => $desired_slug, + ) ); } - return $source; + } elseif ( empty( $to_path ) ) { + return new WP_Error( + 'packaged_wrong', + esc_html__( 'The remote plugin package consists of more than one file, but the files are not packaged in a folder.', 'zero-bs-crm' ) . ' ' . esc_html__( 'Please contact the plugin provider and ask them to package their plugin according to the WordPress guidelines.', 'zero-bs-crm' ), + array( + 'found' => $to_path, + 'expected' => $desired_slug, + ) + ); } + return $source; + } - - - /* =============================================================================================== + /* + =============================================================================================== ==================================== / helper functions ========================================== - =============================================================================================== */ + =============================================================================================== + */ } -//https://stackoverflow.com/questions/2053245/how-can-i-detect-if-the-user-is-on-localhost-in-php +// https://stackoverflow.com/questions/2053245/how-can-i-detect-if-the-user-is-on-localhost-in-php // fullCheck = true = also checks in with our sever (max 1 x 24h) to see if we have an override rule in place // defaults to full check as of 2.97.9 // SELECT * FROM `zbs_app_users_licenses_requests` WHERE action = 'localcheck' -function zeroBSCRM_isLocal($fullCheck=true) { +function zeroBSCRM_isLocal( $fullCheck = true ) { // quick caching - if (jpcrm_is_devmode_override()) return false; + if ( jpcrm_is_devmode_override() ) { + return false; + } // is local, unless override setting set within past 48h $whitelist = array( '127.0.0.1', 'localhost', '::1' ); if ( in_array( zeroBSCRM_getRealIpAddr(), $whitelist, true ) ) { - if ($fullCheck){ - - global $zbs; - - // appears to be local - // see if setting (if this is set, it's legit, and its the last timestamp it was 'checked') - $key = $zbs->DAL->setting('localoverride',false); - // debug echo 'settinglocal:'.$key.' vs '.(time()-172800).'!
'; + if ( $fullCheck ) { - // how often to recheck - $ageOkay = time()-(7*86400); + global $zbs; - // if set, less than xxx ago - if ($key !== false && $key > $ageOkay) - return false; // it appears not to be dev mode - else { - - // is probably dev mode, if last check was more than xxx days ago, recheck - $lastcheck = $zbs->DAL->setting('localoverridecheck',false); - // debug echo 'lastcheck:'.$lastcheck.'!
'; + // appears to be local + // see if setting (if this is set, it's legit, and its the last timestamp it was 'checked') + $key = $zbs->DAL->setting( 'localoverride', false ); + // debug echo 'settinglocal:'.$key.' vs '.(time()-172800).'!
'; - // has last check - if ($lastcheck !== false && $lastcheck > $ageOkay) - // was checked less than a day ago, so is probs dev mode - return true; - else { + // how often to recheck + $ageOkay = time() - ( 7 * 86400 ); - // check + return - $check = zeroBSCRM_localDblCheck(); - - // debug echo 'check:'.$check.'!
'; + // if set, less than xxx ago + if ( $key !== false && $key > $ageOkay ) { + return false; // it appears not to be dev mode + } else { - return $check; + // is probably dev mode, if last check was more than xxx days ago, recheck + $lastcheck = $zbs->DAL->setting( 'localoverridecheck', false ); + // debug echo 'lastcheck:'.$lastcheck.'!
'; - } + // has last check + if ( $lastcheck !== false && $lastcheck > $ageOkay ) { + // was checked less than a day ago, so is probs dev mode + return true; + } else { - } + // check + return + $check = zeroBSCRM_localDblCheck(); - } else { + // debug echo 'check:'.$check.'!
'; - // non-full-check - return true; - } + return $check; - } + } + } + } else { - return false; + // non-full-check + return true; + } + } + return false; } /* - This function connects to https://api.jetpackcrm.com/localcheck ... passing this site url ... it's to be used to test if we have an "override" logged for this siteurl ... (to say that it's NOT a dev server, at this site url.) - .. this should only ever be run once a day or so max, as calls API. + .. this should only ever be run once a day or so max, as calls API. .. in this case it's called by zeroBSCRM_isLocal itself, on param */ -function zeroBSCRM_localDblCheck(){ +function zeroBSCRM_localDblCheck() { // quick caching - if (jpcrm_is_devmode_override()) return false; + if ( jpcrm_is_devmode_override() ) { + return false; + } - // req. + // req. global $zbs; // build request data package $api_params = array( - 'siteurl' => home_url(), - 'method' => 'POST', + 'siteurl' => home_url(), + 'method' => 'POST', ); // run the req. - $responseFull = wp_remote_post( $zbs->urls['apilocalcheck'], array( - 'method' => 'POST', - 'timeout' => 60, - 'redirection' => 5, - 'httpversion' => '1.0', - 'blocking' => true, - 'headers' => array(), - 'body' => $api_params, - 'cookies' => array() - ) + $responseFull = wp_remote_post( + $zbs->urls['apilocalcheck'], + array( + 'method' => 'POST', + 'timeout' => 60, + 'redirection' => 5, + 'httpversion' => '1.0', + 'blocking' => true, + 'headers' => array(), + 'body' => $api_params, + 'cookies' => array(), + ) ); // log that it was checked - $zbs->DAL->updateSetting('localoverridecheck',time()); + $zbs->DAL->updateSetting( 'localoverridecheck', time() ); // got wp err? - if ( ! is_wp_error( $responseFull ) ) { - - // decode - $response = json_decode( $responseFull['body'],true ); + if ( ! is_wp_error( $responseFull ) ) { - // infer - if (isset($response['overridemode']) && $response['overridemode'] == 1){ + // decode + $response = json_decode( $responseFull['body'], true ); - //debug echo home_url().' is override'; - // is legit, set here + Return false, this is to be override (not a local site) - $zbs->DAL->updateSetting('localoverride',time()); + // infer + if ( isset( $response['overridemode'] ) && $response['overridemode'] == 1 ) { - // we also set this runtime global to avoid us having to multicheck settings - define('JPCRM_DEVOVERRIDE',true); + // debug echo home_url().' is override'; + // is legit, set here + Return false, this is to be override (not a local site) + $zbs->DAL->updateSetting( 'localoverride', time() ); - return false; - - } else { - - // debug echo home_url().' Not override'; - // nope. not override (return true, is a local site) - return true; - - } + // we also set this runtime global to avoid us having to multicheck settings + define( 'JPCRM_DEVOVERRIDE', true ); + return false; } else { - // log the err - //$zbs->DAL->updateSetting('licensingerror',array('time'=>time(), 'err' => $responseFull->get_error_message())); + // debug echo home_url().' Not override'; + // nope. not override (return true, is a local site) + return true; } + } else { - // nope. not override (return true, is a local site) - return true; + // log the err + // $zbs->DAL->updateSetting('licensingerror',array('time'=>time(), 'err' => $responseFull->get_error_message())); } + // nope. not override (return true, is a local site) + return true; +} // checks if a plugin has an update. // adapted from https://wordpress.stackexchange.com/questions/228468/plugin-update-warning // name = Jetpack CRM // textdom = zero-bs-crm (in lieu of slug) - function zeroBSCRM_updates_pluginHasUpdate($name='',$textDomain=''){ +function zeroBSCRM_updates_pluginHasUpdate( $name = '', $textDomain = '' ) { - if ( ! function_exists( 'get_plugin_updates' ) ) { - require_once ABSPATH . 'wp-admin/includes/update.php'; - require_once ABSPATH . 'wp-admin/includes/plugin.php'; - } + if ( ! function_exists( 'get_plugin_updates' ) ) { + require_once ABSPATH . 'wp-admin/includes/update.php'; + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } - $list = get_plugin_updates(); - $data = array(); + $list = get_plugin_updates(); + $data = array(); - foreach( $list as $i => $item ) { - - // debug echo 'item:
'.print_r($item,1).'

'; + foreach ( $list as $i => $item ) { - if ( - (!empty($name) && strtolower( $name ) == strtolower( $item->Name ) ) - || - (!empty($textDomain) && strtolower( $textDomain ) == strtolower( $item->TextDomain ) ) - ) { + // debug echo 'item:
'.print_r($item,1).'

'; - // simpler... - return $list[$i]; - } - } + if ( ( ! empty( $name ) && strtolower( $name ) == strtolower( $item->Name ) ) + || + ( ! empty( $textDomain ) && strtolower( $textDomain ) == strtolower( $item->TextDomain ) ) + ) { - /* not req. - if( ! empty( $data ) ) { + // simpler... + return $list[ $i ]; + } + } - return array( - 'name' => $data->Name, - 'version' => $data->Version, - 'new_version' => $data->update->new_version, - 'url' => $data->update->url, - 'package' => $data->update->package - ); + /* + not req. + if( ! empty( $data ) ) { + + return array( + 'name' => $data->Name, + 'version' => $data->Version, + 'new_version' => $data->update->new_version, + 'url' => $data->update->url, + 'package' => $data->update->package + ); - } */ + } */ - return array(); + return array(); } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.REST.php b/projects/plugins/crm/includes/ZeroBSCRM.REST.php index d191aeefe746..ec096c9192a3 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.REST.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.REST.php @@ -1,5 +1,5 @@ - 'GET', - 'callback' => 'zeroBSCRM_rest_getCompanies', - 'args' => array( - /* not implemented? - wh, see http://v2.wp-api.org/extending/adding/ arguments - 'id' => array( - 'validate_callback' => 'is_numeric' - ), */ - ), - 'permission_callback' => function () { - return zeroBSCRM_permsCustomers(); //permissions. - } - - ) ); - - register_rest_route( 'zbscrm/v1', '/contacts/', array( - 'methods' => 'GET', - 'callback' => 'zeroBSCRM_rest_getContacts', - 'args' => array( - /*'id' => array( - 'validate_callback' => 'is_numeric' - ),*/ - ), - 'permission_callback' => function () { - return zeroBSCRM_permsCustomers(); //permissions. - } - - ) ); - - - #}additional here for v3.0 type-ahead. Used to get both companies AND contacts the array will hold - #} ID, email, object_id - #} concom = con[tact]com[pany] - - register_rest_route( 'zbscrm/v1', '/concom/', array( - 'methods' => 'POST, GET', - 'callback' => 'zeroBSCRM_rest_getConCom', - 'args' => array( - /*'id' => array( - 'validate_callback' => 'is_numeric' - ),*/ - ), - 'permission_callback' => function () { - return zeroBSCRM_permsCustomers(); //permissions. - } - - ) ); - - /** - * Feature flag to conditionally load in development API. - * - * @ignore - * @since 6.1.0 - * - * @param bool Determine if we should initialize the new REST APIs. - */ - if ( apply_filters( 'jetpack_crm_feature_flag_api_v4', false ) ) { - $controller = new Automattic\Jetpack\CRM\REST_API\V4\REST_Contacts_Controller(); - $controller->register_routes(); - - $automation_controller = new Automattic\Jetpack\CRM\REST_API\V4\REST_Automation_Workflows_Controller(); - $automation_controller->register_routes(); +add_action( + 'rest_api_init', + function () { + #} sites come with this enabled (but require non-plain permalinks) + register_rest_route( + 'zbscrm/v1', + '/companies/', + array( + 'methods' => 'GET', + 'callback' => 'zeroBSCRM_rest_getCompanies', + 'args' => array( + /* + not implemented? + wh, see http://v2.wp-api.org/extending/adding/ arguments + 'id' => array( + 'validate_callback' => 'is_numeric' + ), */ + ), + 'permission_callback' => function () { + return zeroBSCRM_permsCustomers(); // permissions. + }, + + ) + ); + + register_rest_route( + 'zbscrm/v1', + '/contacts/', + array( + 'methods' => 'GET', + 'callback' => 'zeroBSCRM_rest_getContacts', + 'args' => array( + /* + 'id' => array( + 'validate_callback' => 'is_numeric' + ),*/ + ), + 'permission_callback' => function () { + return zeroBSCRM_permsCustomers(); // permissions. + }, + + ) + ); + + #}additional here for v3.0 type-ahead. Used to get both companies AND contacts the array will hold + #} ID, email, object_id + #} concom = con[tact]com[pany] + + register_rest_route( + 'zbscrm/v1', + '/concom/', + array( + 'methods' => 'POST, GET', + 'callback' => 'zeroBSCRM_rest_getConCom', + 'args' => array( + /* + 'id' => array( + 'validate_callback' => 'is_numeric' + ),*/ + ), + 'permission_callback' => function () { + return zeroBSCRM_permsCustomers(); // permissions. + }, + + ) + ); + + /** + * Feature flag to conditionally load in development API. + * + * @ignore + * @since 6.1.0 + * + * @param bool Determine if we should initialize the new REST APIs. + */ + if ( apply_filters( 'jetpack_crm_feature_flag_api_v4', false ) ) { + $controller = new Automattic\Jetpack\CRM\REST_API\V4\REST_Contacts_Controller(); + $controller->register_routes(); + + $automation_controller = new Automattic\Jetpack\CRM\REST_API\V4\REST_Automation_Workflows_Controller(); + $automation_controller->register_routes(); + } } -}); - -//the callbacks (for the above URLS - restricted by the permission_callback above). -function zeroBSCRM_rest_getCompanies(WP_REST_Request $request){ - - // as per http://v2.wp-api.org/extending/adding/ (argument section): - $searchQuery = ''; if (isset($request['s'])) $searchQuery = sanitize_text_field( $request['s'] ); - $potentialID = -1; if (isset($request['id'])) $potentialID = (int)sanitize_text_field( $request['id'] ); - - // if id, pass back obj singular - if ($potentialID > 0) return zeroBS_getCompany($potentialID); - +); - $ret = array(); - // $ret = zeroBS_getCompanies(true,100000,0); - $ret = zeroBS_getCompaniesForTypeahead($searchQuery); // limitless simplified query (for now) - $retA = array(); - foreach ($ret as $r){ - if (isset($r['name']) && $r['name'] !== 'Auto Draft') $retA[] = $r; - } - $ret = $retA; unset($retA); - return $ret; -} - -function zeroBSCRM_rest_getContacts(WP_REST_Request $request){ - - global $zbs; - - // as per http://v2.wp-api.org/extending/adding/ (argument section): - $searchQuery = ''; if (isset($request['s'])) $searchQuery = sanitize_text_field( $request['s'] ); - $potentialID = -1; if (isset($request['id'])) $potentialID = (int)sanitize_text_field( $request['id'] ); +// the callbacks (for the above URLS - restricted by the permission_callback above). +function zeroBSCRM_rest_getCompanies( WP_REST_Request $request ) { - // if id, pass back obj singular - if ($potentialID > 0) return zeroBS_getCustomer($potentialID); - - /* WH temp rewrite. This shouldn't really be autocaching 100k contacts... but for now, at least get via LEAN SQL, - if DAL3+ */ + // as per http://v2.wp-api.org/extending/adding/ (argument section): + $searchQuery = ''; + if ( isset( $request['s'] ) ) { + $searchQuery = sanitize_text_field( $request['s'] ); + } + $potentialID = -1; + if ( isset( $request['id'] ) ) { + $potentialID = (int) sanitize_text_field( $request['id'] ); + } - // Contacts - - $retA = $zbs->DAL->contacts->getContacts(array( - 'simplified' => true, - 'searchPhrase' => $searchQuery - )); + // if id, pass back obj singular + if ( $potentialID > 0 ) { + return zeroBS_getCompany( $potentialID ); + } - return $retA; + $ret = array(); + // $ret = zeroBS_getCompanies(true,100000,0); + $ret = zeroBS_getCompaniesForTypeahead( $searchQuery ); // limitless simplified query (for now) + $retA = array(); + foreach ( $ret as $r ) { + if ( isset( $r['name'] ) && $r['name'] !== 'Auto Draft' ) { + $retA[] = $r; + } + } + $ret = $retA; + unset( $retA ); + return $ret; } -function zeroBSCRM_rest_getConCom(WP_REST_Request $request){ +function zeroBSCRM_rest_getContacts( WP_REST_Request $request ) { - global $zbs; + global $zbs; - // as per http://v2.wp-api.org/extending/adding/ (argument section): - $searchQuery = ''; if (isset($request['s'])) $searchQuery = sanitize_text_field( $request['s'] ); - $potentialID = -1; if (isset($request['id'])) $potentialID = (int)sanitize_text_field( $request['id'] ); - $objectType = -1; if (isset($request['obj_type'])) $potentialID = (int)sanitize_text_field( $request['obj_type'] ); - - // if id, pass back obj simpler, but now also take in objectType too. - if ($potentialID > 0 && $objectType == ZBS_TYPE_CONTACT) return zeroBS_getCustomer($potentialID); - if ($potentialID > 0 && $objectType == ZBS_TYPE_COMPANY) return zeroBS_getCompany($potentialID); + // as per http://v2.wp-api.org/extending/adding/ (argument section): + $searchQuery = ''; + if ( isset( $request['s'] ) ) { + $searchQuery = sanitize_text_field( $request['s'] ); + } + $potentialID = -1; + if ( isset( $request['id'] ) ) { + $potentialID = (int) sanitize_text_field( $request['id'] ); + } - // ultimate return - $retA = array(); + // if id, pass back obj singular + if ( $potentialID > 0 ) { + return zeroBS_getCustomer( $potentialID ); + } - /* WH temp rewrite. This shouldn't really be autocaching 100k contacts... but for now, at least get via LEAN SQL, - if DAL3+ */ + /* + WH temp rewrite. This shouldn't really be autocaching 100k contacts... but for now, at least get via LEAN SQL, + if DAL3+ */ - // Contacts + // Contacts - $retA = $zbs->DAL->contacts->getContacts(array( - 'simplified' => true, - 'searchPhrase' => $searchQuery, - 'sortByField' => 'ID', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 300, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_CONTACT) - )); + $retA = $zbs->DAL->contacts->getContacts( + array( + 'simplified' => true, + 'searchPhrase' => $searchQuery, + ) + ); - // quickly cycle through + add obj_type + name/email ... inefficient - if (is_array($retA) && count($retA) > 0) - for ($i = 0; $i < count($retA); $i++){ + return $retA; +} - $retA[$i]['name_email'] = $retA[$i]['email'].' '.$retA[$i]['name']; - $retA[$i]['obj_type'] = 1; +function zeroBSCRM_rest_getConCom( WP_REST_Request $request ) { - } - else - $retA = array(); + global $zbs; - // Companies - - $retB = array(); - $retB = $zbs->DAL->companies->getCompanies(array( - 'simplified' => true, - 'searchPhrase' => $searchQuery, - 'sortByField' => 'ID', - 'sortOrder' => 'DESC', - 'page' => 0, - 'perPage' => 300, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership(ZBS_TYPE_COMPANY) - )); + // as per http://v2.wp-api.org/extending/adding/ (argument section): + $searchQuery = ''; + if ( isset( $request['s'] ) ) { + $searchQuery = sanitize_text_field( $request['s'] ); + } + $potentialID = -1; + if ( isset( $request['id'] ) ) { + $potentialID = (int) sanitize_text_field( $request['id'] ); + } + $objectType = -1; + if ( isset( $request['obj_type'] ) ) { + $potentialID = (int) sanitize_text_field( $request['obj_type'] ); + } - // quickly cycle through + add obj_type + name/email ... inefficient - if (is_array($retB) && count($retB) > 0) - for ($i = 0; $i < count($retB); $i++){ + // if id, pass back obj simpler, but now also take in objectType too. + if ( $potentialID > 0 && $objectType == ZBS_TYPE_CONTACT ) { + return zeroBS_getCustomer( $potentialID ); + } + if ( $potentialID > 0 && $objectType == ZBS_TYPE_COMPANY ) { + return zeroBS_getCompany( $potentialID ); + } - $retB[$i]['name_email'] = $retB[$i]['email'].' '.$retB[$i]['name']; - $retB[$i]['obj_type'] = 2; + // ultimate return + $retA = array(); + + /* + WH temp rewrite. This shouldn't really be autocaching 100k contacts... but for now, at least get via LEAN SQL, + if DAL3+ */ + + // Contacts + + $retA = $zbs->DAL->contacts->getContacts( + array( + 'simplified' => true, + 'searchPhrase' => $searchQuery, + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 300, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); + + // quickly cycle through + add obj_type + name/email ... inefficient + if ( is_array( $retA ) && count( $retA ) > 0 ) { + for ( $i = 0; $i < count( $retA ); $i++ ) { + + $retA[ $i ]['name_email'] = $retA[ $i ]['email'] . ' ' . $retA[ $i ]['name']; + $retA[ $i ]['obj_type'] = 1; + + } + } else { + $retA = array(); + } - } + // Companies + + $retB = array(); + $retB = $zbs->DAL->companies->getCompanies( + array( + 'simplified' => true, + 'searchPhrase' => $searchQuery, + 'sortByField' => 'ID', + 'sortOrder' => 'DESC', + 'page' => 0, + 'perPage' => 300, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_COMPANY ), + ) + ); + + // quickly cycle through + add obj_type + name/email ... inefficient + if ( is_array( $retB ) && count( $retB ) > 0 ) { + for ( $i = 0; $i < count( $retB ); $i++ ) { + + $retB[ $i ]['name_email'] = $retB[ $i ]['email'] . ' ' . $retB[ $i ]['name']; + $retB[ $i ]['obj_type'] = 2; + + } + } - $retA = array_merge($retA,$retB); - unset($retB); + $retA = array_merge( $retA, $retB ); + unset( $retB ); - return $retA; + return $retA; } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.ScreenOptions.php b/projects/plugins/crm/includes/ZeroBSCRM.ScreenOptions.php index ee9128de5836..ba6e758d8636 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.ScreenOptions.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.ScreenOptions.php @@ -1,5 +1,5 @@ -global_screen_options(); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + $screenOptionsHTML = ''; + $options = array(); + $rights = true; // this is 'okay for everyone' - current_user_can('administrator')? + $screenOpts = $zbs->global_screen_options(); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - switch ($zbs->pageKey){ + switch ( $zbs->pageKey ) { // contact edit case 'zbs-add-edit-contact-edit': - $options['metaboxes'] = zeroBSCRM_getCurrentMetaboxesFlatArr(); break; // company view case 'zbs-add-edit-company-view': - $options['tablecolumns'] = array(); - // global $zbsTransactionFields; - // get existing from setting - $activeTransactionColumns = array('date','id','total','status'); // default + // global $zbsTransactionFields; + // get existing from setting + $activeTransactionColumns = array( 'date', 'id', 'total', 'status' ); // default // not from setting, from screenopt $allColumns = zeroBSCRM_getSetting('company_view_docs_columns'); - //if (isset($allColumns['transactions']) && is_array($allColumns['transactions']) && count($allColumns['transactions']) > 0) $zbsTransactionFields = $allColumns['transactions']; + // if (isset($allColumns['transactions']) && is_array($allColumns['transactions']) && count($allColumns['transactions']) > 0) $zbsTransactionFields = $allColumns['transactions']; if ( - isset($screenOpts) && is_array($screenOpts) - && isset($screenOpts['tablecolumns']) && is_array($screenOpts['tablecolumns']) - && isset($screenOpts['tablecolumns']['transactions']) - && is_array($screenOpts['tablecolumns']['transactions']) - && count($screenOpts['tablecolumns']['transactions']) > 0 - ) $activeTransactionColumns = $screenOpts['tablecolumns']['transactions']; + isset( $screenOpts ) && is_array( $screenOpts ) + && isset( $screenOpts['tablecolumns'] ) && is_array( $screenOpts['tablecolumns'] ) + && isset( $screenOpts['tablecolumns']['transactions'] ) + && is_array( $screenOpts['tablecolumns']['transactions'] ) + && count( $screenOpts['tablecolumns']['transactions'] ) > 0 + ) { + $activeTransactionColumns = $screenOpts['tablecolumns']['transactions']; + } $options['tablecolumns']['transactions'] = $activeTransactionColumns; @@ -54,149 +56,167 @@ function zeroBSCRM_screenOptionsPanel(){ } // build html - if (count($options) > 0){ + if ( count( $options ) > 0 ) { // build metabox show/hide - if (isset($options['metaboxes'])){ + if ( isset( $options['metaboxes'] ) ) { // get hidden list - $hidden = array(); if (is_array($screenOpts) && isset($screenOpts['mb_hidden']) && is_array($screenOpts['mb_hidden'])) $hidden = $screenOpts['mb_hidden']; - - // allow rearrange? - // Don't use anymore :) MS UI input $rearrangeButton = ''; - $rearrangeButton = ''; + $hidden = array(); + if ( is_array( $screenOpts ) && isset( $screenOpts['mb_hidden'] ) && is_array( $screenOpts['mb_hidden'] ) ) { + $hidden = $screenOpts['mb_hidden']; + } - // build html list - $screenOptionsHTML .= '
'.__('Boxes','zero-bs-crm').$rearrangeButton.'
'; + // allow rearrange? + // Don't use anymore :) MS UI input $rearrangeButton = ''; + $rearrangeButton = ''; + + // build html list + $screenOptionsHTML .= '
' . __( 'Boxes', 'zero-bs-crm' ) . $rearrangeButton . '
'; // show lists - normal - if (isset($options['metaboxes']['normal']) && is_array($options['metaboxes']['normal']) && count($options['metaboxes']['normal']) > 0){ - - // for now, just doing lines $screenOptionsHTML .= '
'; - $screenOptionsHTML .= '

'.__('Main Column','zero-bs-crm').'

'; - foreach ($options['metaboxes']['normal'] as $mbID => $mb){ + if ( isset( $options['metaboxes']['normal'] ) && is_array( $options['metaboxes']['normal'] ) && count( $options['metaboxes']['normal'] ) > 0 ) { - $mbTitle = $mbID; if (is_array($mb) && isset($mb['title'])) $mbTitle = $mb['title']; + // for now, just doing lines $screenOptionsHTML .= '
'; + $screenOptionsHTML .= '

' . __( 'Main Column', 'zero-bs-crm' ) . '

'; + foreach ( $options['metaboxes']['normal'] as $mbID => $mb ) { - // if can hide - $canHide = true; if (isset($mb['capabilities']) && isset($mb['capabilities']['can_hide']) && $mb['capabilities']['can_hide'] == false) $canHide = false; + $mbTitle = $mbID; + if ( is_array( $mb ) && isset( $mb['title'] ) ) { + $mbTitle = $mb['title']; + } - if ($canHide){ + // if can hide + $canHide = true; + if ( isset( $mb['capabilities'] ) && isset( $mb['capabilities']['can_hide'] ) && $mb['capabilities']['can_hide'] == false ) { + $canHide = false; + } - $screenOptionsHTML .= '
'.$mbTitle.'
'; - - } else { + if ( $canHide ) { - $screenOptionsHTML .= '
'; - + $screenOptionsHTML .= '
' . $mbTitle . '
'; + + } else { + + $screenOptionsHTML .= '
'; } - $screenOptionsHTML .= '
'; + } + $screenOptionsHTML .= '
'; - } + } // show list - side - if (isset($options['metaboxes']['side']) && is_array($options['metaboxes']['side']) && count($options['metaboxes']['side']) > 0){ - - // for now, just doing lines $screenOptionsHTML .= '
'; - $screenOptionsHTML .= '

'.__('Side','zero-bs-crm').'

'; - foreach ($options['metaboxes']['side'] as $mbID => $mb){ + if ( isset( $options['metaboxes']['side'] ) && is_array( $options['metaboxes']['side'] ) && count( $options['metaboxes']['side'] ) > 0 ) { - $mbTitle = $mbID; if (is_array($mb) && isset($mb['title'])) $mbTitle = $mb['title']; + // for now, just doing lines $screenOptionsHTML .= '
'; + $screenOptionsHTML .= '

' . __( 'Side', 'zero-bs-crm' ) . '

'; + foreach ( $options['metaboxes']['side'] as $mbID => $mb ) { - // if can hide - $canHide = true; if (isset($mb['capabilities']) && isset($mb['capabilities']['can_hide']) && $mb['capabilities']['can_hide'] == false) $canHide = false; + $mbTitle = $mbID; + if ( is_array( $mb ) && isset( $mb['title'] ) ) { + $mbTitle = $mb['title']; + } - if ($canHide){ - $screenOptionsHTML .= '
'.$mbTitle.'
'; - } else { + // if can hide + $canHide = true; + if ( isset( $mb['capabilities'] ) && isset( $mb['capabilities']['can_hide'] ) && $mb['capabilities']['can_hide'] == false ) { + $canHide = false; + } - $screenOptionsHTML .= '
'; - + if ( $canHide ) { + $screenOptionsHTML .= '
' . $mbTitle . '
'; + } else { + + $screenOptionsHTML .= '
'; + } - $screenOptionsHTML .= '
'; + } + $screenOptionsHTML .= '
'; - } + } $screenOptionsHTML .= '
'; // end row + grid + group } // build tablecolumns on/off - if (isset($options['tablecolumns']) && is_array($options['tablecolumns']) && count($options['tablecolumns']) > 0){ + if ( isset( $options['tablecolumns'] ) && is_array( $options['tablecolumns'] ) && count( $options['tablecolumns'] ) > 0 ) { // build html list - $screenOptionsHTML .= '
'.__('Document Table Columns','zero-bs-crm').'
'; + $screenOptionsHTML .= '
' . __( 'Document Table Columns', 'zero-bs-crm' ) . '
'; - foreach ($options['tablecolumns'] as $type => $selectedColumns){ + foreach ( $options['tablecolumns'] as $type => $selectedColumns ) { - switch ($type){ + switch ( $type ) { case 'transactions': - // get whole list (of poss columns - list fields, then columns) // these are in two types of arrays, so first, shuffle them into a kinda standardised type global $zbsTransactionFields, $zeroBSCRM_columns_transaction; // exclusions (wh temp workaround) - $excludeColumnKeys = array('customer','customer_name','currency','tagged','added','tax_rate','customeremail'); + $excludeColumnKeys = array( 'customer', 'customer_name', 'currency', 'tagged', 'added', 'tax_rate', 'customeremail' ); $availableColumns = array(); // all fields (inc custom:) - if (isset($zbsTransactionFields) && is_array($zbsTransactionFields) && count($zbsTransactionFields) > 0) foreach ($zbsTransactionFields as $tKey => $tDeets){ - - // key => name - if (!in_array($tKey, $excludeColumnKeys)) $availableColumns[$tKey] = $tDeets[1]; + if ( isset( $zbsTransactionFields ) && is_array( $zbsTransactionFields ) && count( $zbsTransactionFields ) > 0 ) { + foreach ( $zbsTransactionFields as $tKey => $tDeets ) { + // key => name + if ( ! in_array( $tKey, $excludeColumnKeys ) ) { + $availableColumns[ $tKey ] = $tDeets[1]; + } + } } - // all columns (any with same key will override) - if (isset($zeroBSCRM_columns_transaction['all']) && is_array($zeroBSCRM_columns_transaction['all']) && count($zeroBSCRM_columns_transaction['all']) > 0) foreach ($zeroBSCRM_columns_transaction['all'] as $tKey => $tDeets){ - - // key => name - if (!in_array($tKey, $excludeColumnKeys)) $availableColumns[$tKey] = $tDeets[0]; - + // all columns (any with same key will override) + if ( isset( $zeroBSCRM_columns_transaction['all'] ) && is_array( $zeroBSCRM_columns_transaction['all'] ) && count( $zeroBSCRM_columns_transaction['all'] ) > 0 ) { + foreach ( $zeroBSCRM_columns_transaction['all'] as $tKey => $tDeets ) { + + // key => name + if ( ! in_array( $tKey, $excludeColumnKeys ) ) { + $availableColumns[ $tKey ] = $tDeets[0]; + } + } } // show list of cols - if (isset($availableColumns) && is_array($availableColumns) && count($availableColumns) > 0){ - + if ( isset( $availableColumns ) && is_array( $availableColumns ) && count( $availableColumns ) > 0 ) { + // for now, just doing lines $screenOptionsHTML .= '
'; - $screenOptionsHTML .= '

'.__('Transactions Table','zero-bs-crm').'

'; - foreach ($availableColumns as $colKey => $colName){ + $screenOptionsHTML .= '

' . __( 'Transactions Table', 'zero-bs-crm' ) . '

'; + foreach ( $availableColumns as $colKey => $colName ) { - $screenOptionsHTML .= '
'.$colName.'
'; - + $screenOptionsHTML .= '
' . $colName . '
'; } $screenOptionsHTML .= '
'; - } - - + } break; } - - } // foreach type - $screenOptionsHTML .= '
'; // end row + grid + $screenOptionsHTML .= '
'; // end row + grid } // if tablecolumns - } - - if (!empty($screenOptionsHTML)){ + if ( ! empty( $screenOptionsHTML ) ) { ?> '; - - return $ret; + if ( ! empty( $imgHTML ) ) { + $ret .= $imgHTML; + } + $ret .= $html; + if ( ! empty( $detailHTML ) ) { + $ret .= '
' . $detailHTML . '
'; + } + $ret .= '
'; + return $ret; } -function zeroBSCRM_faSocialToSemantic($faClass=''){ +function zeroBSCRM_faSocialToSemantic( $faClass = '' ) { - switch ($faClass){ + switch ( $faClass ) { case 'fa-twitter': - return 'twitter icon'; break; case 'fa-facebook': - return 'facebook icon'; break; case 'fa-linkedin': - return 'linkedin icon'; break; default: - return $faClass; break; } - } #} To match the key to the flag (for button class) the above one pops "icon" on the end -function zeroBSCRM_getSocialIcon($key = ''){ - if($key != ''){ - $socials = array( - 'fb' => 'facebook', - 'tw' => 'twitter', - 'li' => 'linkedin', - 'vk' => 'vk', - 'gp' => 'google plus', - 'in' => 'instagram', - 'yt' => 'youtube' - ); - - if(array_key_exists($key, $socials)){ - return $socials[$key]; - } - } - return false; +function zeroBSCRM_getSocialIcon( $key = '' ) { + if ( $key != '' ) { + $socials = array( + 'fb' => 'facebook', + 'tw' => 'twitter', + 'li' => 'linkedin', + 'vk' => 'vk', + 'gp' => 'google plus', + 'in' => 'instagram', + 'yt' => 'youtube', + ); + + if ( array_key_exists( $key, $socials ) ) { + return $socials[ $key ]; + } } + return false; +} /** * Generates HTML markup for a message box. @@ -112,16 +112,21 @@ function jpcrm_loading_container() { return '
'; } -function zeroBSCRM_UI2_squareFeedbackUpsell($title='',$desc='',$linkStr='',$linkTarget='',$extraClasses=''){ +function zeroBSCRM_UI2_squareFeedbackUpsell( $title = '', $desc = '', $linkStr = '', $linkTarget = '', $extraClasses = '' ) { $html = ''; - $html .= '
'; - if (!empty($title)) $html .= '

'.$title.'

'; - if (!empty($desc)) $html .= '

'.$desc.'

'; - if (!empty($linkTarget) && !empty($linkStr)) $html .= ''.$linkStr.''; - $html .= '
'; - + $html .= '
'; + if ( ! empty( $title ) ) { + $html .= '

' . $title . '

'; + } + if ( ! empty( $desc ) ) { + $html .= '

' . $desc . '

'; + } + if ( ! empty( $linkTarget ) && ! empty( $linkStr ) ) { + $html .= '' . $linkStr . ''; + } + $html .= '
'; return $html; } diff --git a/projects/plugins/crm/includes/ZeroBSCRM.Social.php b/projects/plugins/crm/includes/ZeroBSCRM.Social.php index 916b290ef2bc..a302e6b0a628 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.Social.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.Social.php @@ -1,5 +1,5 @@ - array( + 'name' => 'Twitter', + 'slug' => 'twitter', + 'placeholder' => 'example', + 'fa' => 'fa-twitter', + 'urlprefix' => 'https://twitter.com/', + ), + 'li' => array( + 'name' => 'Linked In', + 'slug' => 'linked-in', + 'placeholder' => 'example', + 'fa' => 'fa-linkedin', + 'urlprefix' => 'https://www.linkedin.com/in/', + ), + 'fb' => array( + 'name' => 'Facebook', + 'slug' => 'facebook', + 'placeholder' => 'example', + 'fa' => 'fa-facebook', + 'urlprefix' => 'https://fb.com/', + ), + + ); + + /* + ====================================================== + / Hard Coded Social Types + ====================================================== + */ + + /* + ====================================================== + Social helper funcs + ====================================================== + */ + + // returns an url (E.g. https://twitter.com/woodyhayday) from a social acc obj + function zeroBSCRM_getSocialLink( $key, $userSocialAccs ) { + + if ( isset( $key ) && isset( $userSocialAccs ) && is_array( $userSocialAccs ) ) { + + global $zbsSocialAccountTypes; + + // got acc? + if ( isset( $userSocialAccs[ $key ] ) && ! empty( $userSocialAccs[ $key ] ) ) { + + // get prefix + $URL = $zbsSocialAccountTypes[ $key ]['urlprefix']; + + // finish it off + return + return $URL . $userSocialAccs[ $key ]; + + } + } - - -/* ====================================================== - Hard Coded Social Types - ====================================================== */ - - global $zbsSocialAccountTypes; - - /* - WH added 2.2 - this drives what "social accounts" are shown everywhere for contacts etc. - - */ - - $zbsSocialAccountTypes = array( - - - 'tw' => array( - 'name' => 'Twitter', - 'slug' => 'twitter', - 'placeholder' => 'example', - 'fa' => 'fa-twitter', - 'urlprefix' => 'https://twitter.com/' - ), - 'li' => array( - 'name' => 'Linked In', - 'slug' => 'linked-in', - 'placeholder' => 'example', - 'fa' => 'fa-linkedin', - 'urlprefix' => 'https://www.linkedin.com/in/' - ), - 'fb' => array( - 'name' => 'Facebook', - 'slug' => 'facebook', - 'placeholder' => 'example', - 'fa' => 'fa-facebook', - 'urlprefix' => 'https://fb.com/' - ) - - - ); - -/* ====================================================== - / Hard Coded Social Types - ====================================================== */ - - - - -/* ====================================================== - Social helper funcs - ====================================================== */ - - // returns an url (E.g. https://twitter.com/woodyhayday) from a social acc obj - function zeroBSCRM_getSocialLink( $key, $userSocialAccs ){ - - if (isset($key) && isset($userSocialAccs) && is_array($userSocialAccs)){ - - global $zbsSocialAccountTypes; - - // got acc? - if (isset($userSocialAccs[$key]) && !empty($userSocialAccs[$key])){ - - // get prefix - $URL = $zbsSocialAccountTypes[$key]['urlprefix']; - - // finish it off + return - return $URL . $userSocialAccs[$key]; - - } - - } - - return '#'; - - } + return '#'; + } /** * Shows business social links diff --git a/projects/plugins/crm/includes/ZeroBSCRM.SystemChecks.php b/projects/plugins/crm/includes/ZeroBSCRM.SystemChecks.php index 46c1cf73ae1f..8120149b7c66 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.SystemChecks.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.SystemChecks.php @@ -1,5 +1,5 @@ -get_fonts(); + global $zbs; - if (!$withInfo) - return $fonts->default_fonts_installed(); - else { + $fonts = $zbs->get_fonts(); - $enabled = $fonts->default_fonts_installed(); - if ( $enabled ){ - $enabledStr = __( "Font installed", 'zero-bs-crm' ); - } else { - $enabledStr = sprintf( __( 'Font not installed (reinstall pdf engine module)', 'zero-bs-crm' ), jpcrm_esc_link( $zbs->slugs['modules'] ) ); - } + if ( ! $withInfo ) { + return $fonts->default_fonts_installed(); + } else { - return array($enabled, $enabledStr); + $enabled = $fonts->default_fonts_installed(); + if ( $enabled ) { + $enabledStr = __( 'Font installed', 'zero-bs-crm' ); + } else { + $enabledStr = sprintf( __( 'Font not installed (reinstall pdf engine module)', 'zero-bs-crm' ), jpcrm_esc_link( $zbs->slugs['modules'] ) ); } + + return array( $enabled, $enabledStr ); } +} - function zeroBSCRM_checkSystemFeat_corever($withInfo=false){ - global $zbs; +function zeroBSCRM_checkSystemFeat_corever( $withInfo = false ) { + global $zbs; - if (!$withInfo) - return $zbs::VERSION; - else { - $enabled = true; - $enabled_str = 'Version ' . $zbs::VERSION; + if ( ! $withInfo ) { + return $zbs::VERSION; + } else { + $enabled = true; + $enabled_str = 'Version ' . $zbs::VERSION; - return array( $enabled, $enabled_str ); - } + return array( $enabled, $enabled_str ); } +} - function zeroBSCRM_checkSystemFeat_dbver($withInfo=false){ - global $zbs; +function zeroBSCRM_checkSystemFeat_dbver( $withInfo = false ) { + global $zbs; - if (!$withInfo) - return $zbs->db_version; - else { + if ( ! $withInfo ) { + return $zbs->db_version; + } else { - $enabled = true; - $enabledStr = 'Database Version ' . $zbs->db_version; + $enabled = true; + $enabledStr = 'Database Version ' . $zbs->db_version; - return array($enabled, $enabledStr); - } + return array( $enabled, $enabledStr ); } +} - function zeroBSCRM_checkSystemFeat_dalver($withInfo=false){ - global $zbs; +function zeroBSCRM_checkSystemFeat_dalver( $withInfo = false ) { + global $zbs; - if (!$withInfo) - return $zbs->dal_version; - else { + if ( ! $withInfo ) { + return $zbs->dal_version; + } else { - $enabled = true; - $enabledStr = 'Data Access Layer Version ' . $zbs->dal_version; + $enabled = true; + $enabledStr = 'Data Access Layer Version ' . $zbs->dal_version; - return array($enabled, $enabledStr); - } + return array( $enabled, $enabledStr ); } +} - function zeroBSCRM_checkSystemFeat_phpver($withInfo=false){ +function zeroBSCRM_checkSystemFeat_phpver( $withInfo = false ) { - if (!$withInfo) - return PHP_VERSION; - else { + if ( ! $withInfo ) { + return PHP_VERSION; + } else { - $enabled = true; - $enabledStr = 'PHP Version ' . PHP_VERSION; + $enabled = true; + $enabledStr = 'PHP Version ' . PHP_VERSION; - return array($enabled, $enabledStr); - } + return array( $enabled, $enabledStr ); } +} - function zeroBSCRM_checkSystemFeat_wordpressver($withInfo=false){ - global $wp_version; +function zeroBSCRM_checkSystemFeat_wordpressver( $withInfo = false ) { + global $wp_version; - if (!$withInfo) - return $wp_version; - else { + if ( ! $withInfo ) { + return $wp_version; + } else { - $enabled = true; - $enabledStr = sprintf(__("WordPress Version %s", 'zero-bs-crm'), $wp_version); + $enabled = true; + $enabledStr = sprintf( __( 'WordPress Version %s', 'zero-bs-crm' ), $wp_version ); - return array($enabled, $enabledStr); - } + return array( $enabled, $enabledStr ); } +} +function zeroBSCRM_checkSystemFeat_local( $withInfo = false ) { + $local = zeroBSCRM_isLocal(); - function zeroBSCRM_checkSystemFeat_local($withInfo=false){ - - $local = zeroBSCRM_isLocal(); - - if (!$withInfo) - return !$local; - else { - - $enabled = !$local; - if ($local) - $enabledStr = 'Running Locally
This may cause connectivity issues with SMTP (Emails) and updates/feature downloads.'; - else - $enabledStr = 'Connectivity Okay.'; + if ( ! $withInfo ) { + return ! $local; + } else { - return array($enabled, $enabledStr); + $enabled = ! $local; + if ( $local ) { + $enabledStr = 'Running Locally
This may cause connectivity issues with SMTP (Emails) and updates/feature downloads.'; + } else { + $enabledStr = 'Connectivity Okay.'; } - } - function zeroBSCRM_checkSystemFeat_serverdefaulttime($withInfo=false){ - /*if (function_exists('locale_get_default')) - $locale = locale_get_default(); - else - $locale = Locale::getDefault(); - */ - $tz = date_default_timezone_get(); + return array( $enabled, $enabledStr ); + } +} +function zeroBSCRM_checkSystemFeat_serverdefaulttime( $withInfo = false ) { - if (!$withInfo) - return true; - else { + /* + if (function_exists('locale_get_default')) + $locale = locale_get_default(); + else + $locale = Locale::getDefault(); + */ + $tz = date_default_timezone_get(); + + if ( ! $withInfo ) { + return true; + } else { - $enabled = true; - $enabledStr = $tz; + $enabled = true; + $enabledStr = $tz; - return array($enabled, $enabledStr); - } + return array( $enabled, $enabledStr ); } - function zeroBSCRM_checkSystemFeat_localtime($withInfo=false){ +} +function zeroBSCRM_checkSystemFeat_localtime( $withInfo = false ) { - $enabled = true; + $enabled = true; - if (!$withInfo) - return true; - else { + if ( ! $withInfo ) { + return true; + } else { - $enabledStr = 'CRM Time: '.zeroBSCRM_date_i18n('Y-m-d H:i:s', time() ).' (GMT: '.date_i18n('Y-m-d H:i:s', time(),true).')'; + $enabledStr = 'CRM Time: ' . zeroBSCRM_date_i18n( 'Y-m-d H:i:s', time() ) . ' (GMT: ' . date_i18n( 'Y-m-d H:i:s', time(), true ) . ')'; - return array($enabled, $enabledStr); - } + return array( $enabled, $enabledStr ); } - - // in devmode or not? - function zeroBSCRM_checkSystemFeat_devmode($withInfo=false){ - - $isLocal = zeroBSCRM_isLocal(); +} - if (!$withInfo) - return $isLocal; - else { + // in devmode or not? +function zeroBSCRM_checkSystemFeat_devmode( $withInfo = false ) { - global $zbs; + $isLocal = zeroBSCRM_isLocal(); - $devModeStr = ''; + if ( ! $withInfo ) { + return $isLocal; + } else { - if (!$isLocal){ + global $zbs; - // check if overriden - $key = $zbs->DAL->setting('localoverride',false); + $devModeStr = ''; - // if set, less than 48h ago, is overriden - if ($key !== false && $key > time()-172800) - $devModeStr = __('Production','zero-bs-crm').' (override)'; - else // normal production (99% users) - $devModeStr = __('Production','zero-bs-crm'); + if ( ! $isLocal ) { - } else { + // check if overriden + $key = $zbs->DAL->setting( 'localoverride', false ); - // devmode proper - $devModeStr = __('Developer Mode','zero-bs-crm'); + // if set, less than 48h ago, is overriden + if ( $key !== false && $key > time() - 172800 ) { + $devModeStr = __( 'Production', 'zero-bs-crm' ) . ' (override)'; + } else { // normal production (99% users) + $devModeStr = __( 'Production', 'zero-bs-crm' ); + } + } else { - } + // devmode proper + $devModeStr = __( 'Developer Mode', 'zero-bs-crm' ); - return array($isLocal, $devModeStr); } + + return array( $isLocal, $devModeStr ); } +} // https://wordpress.stackexchange.com/questions/6424/mysql-database-user-which-privileges-are-needed // can we create tables? - function zeroBSCRM_checkSystemFeat_sqlrights($withInfo=false){ +function zeroBSCRM_checkSystemFeat_sqlrights( $withInfo = false ) { - global $wpdb; - - // run check tables - zeroBSCRM_checkTablesExist(); - $lastError = $wpdb->last_error; + global $wpdb; + + // run check tables + zeroBSCRM_checkTablesExist(); + $lastError = $wpdb->last_error; $okay = true; if ( str_contains( $lastError, 'command denied' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $okay = false; } - if (!$withInfo) - return $okay; - else { - - global $zbs; + if ( ! $withInfo ) { + return $okay; + } else { - $enabled = $okay; - if ($enabled) - $enabledStr = __('Appears Okay','zero-bs-crm'); - else - $enabledStr = __('Error','zero-bs-crm').': '.$lastError; + global $zbs; - return array($enabled, $enabledStr); + $enabled = $okay; + if ( $enabled ) { + $enabledStr = __( 'Appears Okay', 'zero-bs-crm' ); + } else { + $enabledStr = __( 'Error', 'zero-bs-crm' ) . ': ' . $lastError; } + + return array( $enabled, $enabledStr ); } +} /** * Get info about the database server engine and version. @@ -309,236 +307,212 @@ function zeroBSCRM_checkSystemFeat_dbserver( $with_info = false ) { // phpcs:ign } // got InnoDB? - function zeroBSCRM_checkSystemFeat_innodb($withInfo=false){ - - if (!$withInfo) - return zeroBSCRM_DB_canInnoDB() ? __('Available','zero-bs-crm') : __('Not Available','zero-bs-crm'); - else { - $innoDB = zeroBSCRM_DB_canInnoDB(); - return array($innoDB, ($innoDB ? __('Available','zero-bs-crm') : __('Not Available','zero-bs-crm'))); - } +function zeroBSCRM_checkSystemFeat_innodb( $withInfo = false ) { + if ( ! $withInfo ) { + return zeroBSCRM_DB_canInnoDB() ? __( 'Available', 'zero-bs-crm' ) : __( 'Not Available', 'zero-bs-crm' ); + } else { + $innoDB = zeroBSCRM_DB_canInnoDB(); + return array( $innoDB, ( $innoDB ? __( 'Available', 'zero-bs-crm' ) : __( 'Not Available', 'zero-bs-crm' ) ) ); } - - +} // below here: https://stackoverflow.com/questions/8744107/increase-max-execution-time-in-php +function zeroBSCRM_checkSystemFeat_executiontime( $withInfo = false ) { - function zeroBSCRM_checkSystemFeat_executiontime($withInfo=false){ - - - $maxExecution = ini_get('max_execution_time'); - - if (!$withInfo) - return $maxExecution; - else { - - $str = $maxExecution.' seconds'; + $maxExecution = ini_get( 'max_execution_time' ); - // catch infinites - if ($maxExecution == '0') $str = 'No Limit'; + if ( ! $withInfo ) { + return $maxExecution; + } else { - return array($maxExecution,$str); + $str = $maxExecution . ' seconds'; + // catch infinites + if ( $maxExecution == '0' ) { + $str = 'No Limit'; } + return array( $maxExecution, $str ); } +} - function zeroBSCRM_checkSystemFeat_memorylimit($withInfo=false){ - - $maxMemory = ini_get('memory_limit'); - - if (!$withInfo) - return $maxMemory; - else { +function zeroBSCRM_checkSystemFeat_memorylimit( $withInfo = false ) { - $str = $maxMemory; + $maxMemory = ini_get( 'memory_limit' ); - return array($maxMemory,$str); + if ( ! $withInfo ) { + return $maxMemory; + } else { - } + $str = $maxMemory; + return array( $maxMemory, $str ); } +} - function zeroBSCRM_checkSystemFeat_postmaxsize($withInfo=false){ - - $post_max_size = ini_get('post_max_size'); - - if (!$withInfo) - return $post_max_size; - else { +function zeroBSCRM_checkSystemFeat_postmaxsize( $withInfo = false ) { - $str = $post_max_size; + $post_max_size = ini_get( 'post_max_size' ); - return array($post_max_size,$str); + if ( ! $withInfo ) { + return $post_max_size; + } else { - } + $str = $post_max_size; + return array( $post_max_size, $str ); } +} - function zeroBSCRM_checkSystemFeat_uploadmaxfilesize($withInfo=false){ - - $upload_max_filesize = ini_get('upload_max_filesize'); - - if (!$withInfo) - return $upload_max_filesize; - else { +function zeroBSCRM_checkSystemFeat_uploadmaxfilesize( $withInfo = false ) { - $str = $upload_max_filesize; + $upload_max_filesize = ini_get( 'upload_max_filesize' ); - return array($upload_max_filesize,$str); + if ( ! $withInfo ) { + return $upload_max_filesize; + } else { - } + $str = $upload_max_filesize; + return array( $upload_max_filesize, $str ); } +} - function zeroBSCRM_checkSystemFeat_wpuploadmaxfilesize($withInfo=false){ - - //https://codex.wordpress.org/Function_Reference/wp_max_upload_size - $wp_max_upload_size = zeroBSCRM_prettyformatBytes(wp_max_upload_size()); - - if (!$withInfo) - return $wp_max_upload_size; - else { +function zeroBSCRM_checkSystemFeat_wpuploadmaxfilesize( $withInfo = false ) { - $str = $wp_max_upload_size; + // https://codex.wordpress.org/Function_Reference/wp_max_upload_size + $wp_max_upload_size = zeroBSCRM_prettyformatBytes( wp_max_upload_size() ); - return array($wp_max_upload_size,$str); + if ( ! $withInfo ) { + return $wp_max_upload_size; + } else { - } + $str = $wp_max_upload_size; + return array( $wp_max_upload_size, $str ); } +} /* - * Encryption method check + * Encryption method check */ - function zeroBSCRM_checkSystemFeat_encryptionmethod( $withInfo = false ){ - - global $zbs; +function zeroBSCRM_checkSystemFeat_encryptionmethod( $withInfo = false ) { - // load encryption - $encryption = $zbs->load_encryption(); + global $zbs; - // any issues? - $return_string = ''; + // load encryption + $encryption = $zbs->load_encryption(); - // check if has flipped fallback previously - $fallback_blocked = zeroBSCRM_getSetting( 'enc_fallback_blocked' ); - if ( !empty( $fallback_blocked ) ) { + // any issues? + $return_string = ''; - $return_string = __( 'Warning! Encryption disabled due to no available encryption method. Please contact support.', 'zero-bs-crm' ); + // check if has flipped fallback previously + $fallback_blocked = zeroBSCRM_getSetting( 'enc_fallback_blocked' ); + if ( ! empty( $fallback_blocked ) ) { - } + $return_string = __( 'Warning! Encryption disabled due to no available encryption method. Please contact support.', 'zero-bs-crm' ); - // check if has flipped fallback previously - $fallback_active = zeroBSCRM_getSetting( 'enc_fallback_active' ); - if ( !empty( $fallback_active ) ) { + } - $return_string = sprintf( __( 'Note: Encryption using fallback method (%s) due to no available encryption method. Please contact support.', 'zero-bs-crm' ), $encryption->cipher_method() ); + // check if has flipped fallback previously + $fallback_active = zeroBSCRM_getSetting( 'enc_fallback_active' ); + if ( ! empty( $fallback_active ) ) { - } + $return_string = sprintf( __( 'Note: Encryption using fallback method (%s) due to no available encryption method. Please contact support.', 'zero-bs-crm' ), $encryption->cipher_method() ); - if ( !$withInfo ){ - - return $encryption->ready_to_encrypt(); + } - } - else { + if ( ! $withInfo ) { - if ( empty( $return_string ) ){ + return $encryption->ready_to_encrypt(); - $return_string = $encryption->cipher_method(); + } else { - } + if ( empty( $return_string ) ) { - return array( $encryption->ready_to_encrypt(), $return_string ); + $return_string = $encryption->cipher_method(); } + return array( $encryption->ready_to_encrypt(), $return_string ); } - +} // https://codex.wordpress.org/Using_Permalinks#Tips_and_Tricks -function zeroBSCRM_checkPrettyPermalinks(){ - if ( get_option('permalink_structure') ) { +function zeroBSCRM_checkPrettyPermalinks() { + if ( get_option( 'permalink_structure' ) ) { return true; - }else{ + } else { return false; } } +/* +====================================================== + / Generic System Check Wrapper/Helper funcs + ====================================================== */ +/* +====================================================== + Specific System Check Wrapper/Helper funcs + ====================================================== */ -/* ====================================================== - / Generic System Check Wrapper/Helper funcs - ====================================================== */ - - -/* ====================================================== - Specific System Check Wrapper/Helper funcs - ====================================================== */ - - function zeroBSCRM_checkSystemFeat_zlib($withInfo=false){ - +function zeroBSCRM_checkSystemFeat_zlib( $withInfo = false ) { - if ( !$withInfo ) - - return class_exists('ZipArchive'); + if ( ! $withInfo ) { - else { + return class_exists( 'ZipArchive' ); - $enabled = class_exists('ZipArchive'); - $str = __('zlib is properly enabled on your server.','zero-bs-crm'); - if ( !$enabled ) { + } else { - $str = __('zlib is disabled on your server.','zero-bs-crm'); + $enabled = class_exists( 'ZipArchive' ); + $str = __( 'zlib is properly enabled on your server.', 'zero-bs-crm' ); + if ( ! $enabled ) { - // see if fallback pclzip is working - if ( class_exists('PclZip') ){ + $str = __( 'zlib is disabled on your server.', 'zero-bs-crm' ); - // it's probably all fine - $enabled = true; - $str .= ' '.__("But don't worry, as the fallback PclZip appears to work.",'zero-bs-crm'); + // see if fallback pclzip is working + if ( class_exists( 'PclZip' ) ) { - } + // it's probably all fine + $enabled = true; + $str .= ' ' . __( "But don't worry, as the fallback PclZip appears to work.", 'zero-bs-crm' ); } - - return array($enabled,$str); - } + return array( $enabled, $str ); } - +} /** - * + * * Verify mb_internal_encoding (required by dompdf) - * */ - function zeroBSCRM_checkSystemFeat_mb_internal_encoding( $withInfo=false ) { - $enabled = function_exists( 'mb_internal_encoding' ); - if ( !$withInfo ) { - return $enabled; - } - - $str = __( 'The mbstring PHP module is properly enabled on your server.', 'zero-bs-crm' ); +function zeroBSCRM_checkSystemFeat_mb_internal_encoding( $withInfo = false ) { + $enabled = function_exists( 'mb_internal_encoding' ); + if ( ! $withInfo ) { + return $enabled; + } - if ( !$enabled ) { - $str = __( 'The mbstring PHP module is disabled on your server, which may prevent PDFs from being generated.', 'zero-bs-crm' ); - } + $str = __( 'The mbstring PHP module is properly enabled on your server.', 'zero-bs-crm' ); - return array( $enabled, $str ); + if ( ! $enabled ) { + $str = __( 'The mbstring PHP module is disabled on your server, which may prevent PDFs from being generated.', 'zero-bs-crm' ); } + return array( $enabled, $str ); +} + /** * Check if Dompdf is installed correctly on the server. * @@ -574,79 +548,73 @@ function zbscrm_check_system_feat_dompdf( $with_info = false ) { ); } - function zeroBSCRM_checkSystemFeat_pdffonts($withInfo=false){ - - // get fonts dir - $fonts_dir = jpcrm_storage_fonts_dir_path(); - $fonts_installed = file_exists( $fonts_dir . 'fonts-info.txt' ); +function zeroBSCRM_checkSystemFeat_pdffonts( $withInfo = false ) { - if (!$withInfo) { - return $fonts_installed; - } else { - - $str = 'PDF fonts appear to be installed on your server.'; - if ( !$fonts_installed ) { - $str = 'PDF fonts do not appear to be installed on your server.'; - } + // get fonts dir + $fonts_dir = jpcrm_storage_fonts_dir_path(); + $fonts_installed = file_exists( $fonts_dir . 'fonts-info.txt' ); - return array($fonts_installed,$str); + if ( ! $withInfo ) { + return $fonts_installed; + } else { + $str = 'PDF fonts appear to be installed on your server.'; + if ( ! $fonts_installed ) { + $str = 'PDF fonts do not appear to be installed on your server.'; } + return array( $fonts_installed, $str ); } - function zeroBSCRM_checkSystemFeat_curl($withInfo=false){ - - - if (!$withInfo) - return function_exists('curl_init'); - else { - - $enabled = function_exists('curl_init'); - $str = 'CURL is enabled on your server.'; - if (!$enabled) $str = 'CURL is not enabled on your server.'; +} +function zeroBSCRM_checkSystemFeat_curl( $withInfo = false ) { - return array($enabled,$str); + if ( ! $withInfo ) { + return function_exists( 'curl_init' ); + } else { + $enabled = function_exists( 'curl_init' ); + $str = 'CURL is enabled on your server.'; + if ( ! $enabled ) { + $str = 'CURL is not enabled on your server.'; } + return array( $enabled, $str ); } - function zeroBSCRM_checkSystemFeat_locale($withInfo=false){ - - - if (!$withInfo) - return true; - else { - - $locale = zeroBSCRM_getLocale(); - $str = 'WordPress Locale is set to '.$locale.''; +} +function zeroBSCRM_checkSystemFeat_locale( $withInfo = false ) { - $str .= ' (Server: '.zeroBSCRM_locale_getServerLocale().')'; + if ( ! $withInfo ) { + return true; + } else { - return array(true,$str); + $locale = zeroBSCRM_getLocale(); + $str = 'WordPress Locale is set to ' . $locale . ''; - } + $str .= ' (Server: ' . zeroBSCRM_locale_getServerLocale() . ')'; + return array( true, $str ); } +} +function zeroBSCRM_checkSystemFeat_assetdir() { - function zeroBSCRM_checkSystemFeat_assetdir(){ - - $potentialDirObj = zeroBSCRM_privatisedDirCheck(); - if (is_array($potentialDirObj) && isset($potentialDirObj['path'])) - $potentialDir = $potentialDirObj['path']; - else - $potentialDir = false; - - $enabled = false; - $enabledStr = 'Using Default WP Upload Library'; + $potentialDirObj = zeroBSCRM_privatisedDirCheck(); + if ( is_array( $potentialDirObj ) && isset( $potentialDirObj['path'] ) ) { + $potentialDir = $potentialDirObj['path']; + } else { + $potentialDir = false; + } - if (!empty($potentialDir)) { - $enabled = true; - $enabledStr = $potentialDir; - } + $enabled = false; + $enabledStr = 'Using Default WP Upload Library'; - return array($enabled, $enabledStr); + if ( ! empty( $potentialDir ) ) { + $enabled = true; + $enabledStr = $potentialDir; } + + return array( $enabled, $enabledStr ); +} diff --git a/projects/plugins/crm/includes/ZeroBSCRM.TagManager.php b/projects/plugins/crm/includes/ZeroBSCRM.TagManager.php index 1b967df4f169..5e2df772fd08 100644 --- a/projects/plugins/crm/includes/ZeroBSCRM.TagManager.php +++ b/projects/plugins/crm/includes/ZeroBSCRM.TagManager.php @@ -1,5 +1,5 @@ - false, //5 (v3.0+) - - 'objType' => false, //transaction - 'singular' => false, //Transaction - 'plural' => false, //Transactions - //'postType' => false, //zerobs_transaction - removed v3.0 + - // renamed 'listViewSlug' v3.0+ 'postPage' => false, //manage-transactions-tags - 'listViewSlug' => false, - 'langLabels' => array( - - ), - 'extraBoxes' => '' // html for extra boxes e.g. upsells :) - - ); 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; - - // we load from DAL defaults, if objType passed (overriding anything passed, if empty/false) +class zeroBSCRM_TagManager { + + private $objTypeID = false; + + // following all set by objTypeID pass, v3.0+ + private $objType = false; + private $singular = false; + private $plural = false; + // v3.0 this was removed private $postType = false; // set in child class 'zerobs_customer' // ONLY USED IN save funcs etc. maybe, potentially just legacy now. + // renamed 'listViewSlug' v3.0+ private $postPage = false; + private $listViewSlug = false; + + // except these: + private $langLabels = false; + private $extraBoxes = ''; + + function __construct( $args = array() ) { + + #} =========== LOAD ARGS ============== + $defaultArgs = array( + + 'objTypeID' => false, // 5 (v3.0+) + + 'objType' => false, // transaction + 'singular' => false, // Transaction + 'plural' => false, // Transactions + // 'postType' => false, //zerobs_transaction - removed v3.0 + + // renamed 'listViewSlug' v3.0+ 'postPage' => false, //manage-transactions-tags + 'listViewSlug' => false, + 'langLabels' => array(), + 'extraBoxes' => '', // html for extra boxes e.g. upsells :) + + ); + 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; + + // we load from DAL defaults, if objType passed (overriding anything passed, if empty/false) if ( ! empty( $objTypeID ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - $objTypeID = (int)$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; + $objTypeID = (int) $objTypeID; + if ( $objTypeID > 0 ) { + // obj type (contact) + $objTypeStr = $zbs->DAL->objTypeKey( $objTypeID ); + if ( ( ! isset( $this->objType ) || $this->objType == false ) && ! empty( $objTypeStr ) ) { + $this->objType = $objTypeStr; + } - // plural - $objPlural = $zbs->DAL->typeStr($objTypeID,true); - if ((!isset($this->plural) || $this->plural == false) && !empty($objPlural)) $this->plural = $objPlural; + // singular + $objSingular = $zbs->DAL->typeStr( $objTypeID ); + if ( ( ! isset( $this->singular ) || $this->singular == false ) && ! empty( $objSingular ) ) { + $this->singular = $objSingular; + } - // listViewSlug - $objSlug = $zbs->DAL->listViewSlugFromObjID($objTypeID); - if ((!isset($this->listViewSlug) || $this->listViewSlug == false) && !empty($objSlug)) $this->listViewSlug = $objSlug; + // 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; + } + } + } + // anything to save? + $this->catchPost(); + } - } + public function catchPost() { - // anything to save? - $this->catchPost(); + // If post, fire do_action + if ( isset( $_POST['zbs-tag-form-master'] ) && $_POST['zbs-tag-form-master'] == $this->objType ) { - } + // fire it + do_action( 'zerobs_save_' . $this->objType . '_tags', $this->objID, $this->obj ); - public function catchPost(){ + } + } - // If post, fire do_action - if (isset($_POST['zbs-tag-form-master']) && $_POST['zbs-tag-form-master'] == $this->objType){ + public function drawTagView() { - // fire it - do_action('zerobs_save_'.$this->objType.'_tags', $this->objID, $this->obj); + if ( empty( $this->objType ) || empty( $this->listViewSlug ) || empty( $this->singular ) || empty( $this->plural ) ) { - } - - } + return 'Error.'; + } - public function drawTagView(){ + global $zbs; - if (empty($this->objType) || empty($this->listViewSlug) || empty($this->singular) || empty($this->plural)){ + ?>
+ - - + + +
- - -

- - singular ) .' '. esc_html__('Field Manager',"zero-bs-crm"); ?> -

+ -
+

+ + singular ) . ' ' . esc_html__( 'Field Manager', 'zero-bs-crm' ); ?> +

- +
-
-
+ -

+
+
+

-
- $col){ - ?>
+ $col ) { - } ?> -
+ ?> +
+ -
- -

+ } + } + ?> +
-
- $col){ +
+
- if ( ! array_key_exists( $colKey, $currentFields ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - - ?>
- } - } ?> -
+
+ $col ) { -
-
-
+ if ( ! array_key_exists( $colKey, $currentFields ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + ?> +
+ +
- - -
- +
+
+
-
- plural,'There has been a problem retrieving your '.$this->singular.', if this issue persists, please contact support.','disabled warning sign','zbsCantLoadData'); - - ?> -
- -
- - 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){ +
+ plural, 'There has been a problem retrieving your ' . $this->singular . ', if this issue persists, please contact support.', 'disabled warning sign', 'zbsCantLoadData' ); - } + ?> +
+ +
- echo '
'; + 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 ) { - ?> + // for now these can be any html :) + echo $msg; -
+ } + echo '
'; - -
+ } - objType ); - ?> + ?> -
- -
- - #} Sidebar metaboxes - zeroBSCRM_do_meta_boxes( 'zerobs_edit_tags', 'side', $this->objType ); - ?> + +
- - extraBoxes; ?> - -
-
+ objType ); + ?> - -
-
+
+ +
+ - objType ); + ?> + + extraBoxes; ?> + +
+
- // make simpler - $tags = $zbs->DAL->getTagsForObjType(array( + +
+
- 'objtypeid'=>$zbs->DAL->objTypeID($this->objType),//ZBS_TYPE_CONTACT in place of 'contact'=>1, 'transaction'=> etc. - 'excludeEmpty'=>false, - 'withCount'=>false, - 'ignoreowner' => true + + + }; + + + $form['id'], 'title' => $form['title'] ); + $ret[] = array( + 'id' => $form['id'], + 'title' => $form['title'], + ); } } - ?> + error_data = $data; parent::__construct( $message . ' (' . $code . ')', 0, null ); - } /** diff --git a/projects/plugins/crm/includes/class-crm-modules.php b/projects/plugins/crm/includes/class-crm-modules.php index f3b26d9cacad..593f41f928d2 100644 --- a/projects/plugins/crm/includes/class-crm-modules.php +++ b/projects/plugins/crm/includes/class-crm-modules.php @@ -1,5 +1,5 @@ -register_modules(); - } /* * Autoloads the modules (core extensions) included with core - * + * * Modularisation of this manner may allow easier drop-in integrations by third-party devs as well. */ - public function register_modules(){ + public function register_modules() { $module_directories = jpcrm_get_directories( JPCRM_MODULES_PATH ); - if ( is_array( $module_directories ) ){ + if ( is_array( $module_directories ) ) { - foreach ( $module_directories as $directory ){ + foreach ( $module_directories as $directory ) { // load module $this->register_module( $directory ); } - } - } /* @@ -53,15 +50,14 @@ public function register_modules(){ * * @param string $module_slug */ - public function register_module( $module_slug ){ + public function register_module( $module_slug ) { // where `jpcrm-{$directory}-init.php` present, include - if ( file_exists( JPCRM_MODULES_PATH . "{$module_slug}/jpcrm-{$module_slug}-init.php" ) ){ - - require_once( JPCRM_MODULES_PATH . "{$module_slug}/jpcrm-{$module_slug}-init.php" ); + if ( file_exists( JPCRM_MODULES_PATH . "{$module_slug}/jpcrm-{$module_slug}-init.php" ) ) { - } + require_once JPCRM_MODULES_PATH . "{$module_slug}/jpcrm-{$module_slug}-init.php"; + } } /* @@ -77,10 +73,9 @@ public function load_module( $module_slug, $module_class ) { // double backslash due to the $ $class_name = "Automattic\JetpackCRM\\$module_class"; - $this->$module_slug = new $class_name; + $this->$module_slug = new $class_name(); return $this->$module_slug; - } /** @@ -101,8 +96,8 @@ public function activate_module_and_redirect() { return; } - $module_name = sanitize_text_field( $_GET['jpcrm-module-name'] ); - $safe_module_name = $this->get_safe_module_string( $module_name ); + $module_name = sanitize_text_field( $_GET['jpcrm-module-name'] ); + $safe_module_name = $this->get_safe_module_string( $module_name ); $safe_function_string = $this->get_safe_function_string( $module_name ); // if module is not installed, try to install it @@ -119,13 +114,13 @@ public function activate_module_and_redirect() { // default to CRM dashboard $redirect_to = jpcrm_esc_link( $zbs->slugs['dash'] ); - //if redirect_to is specified, use that + // if redirect_to is specified, use that if ( isset( $_GET['redirect_to'] ) ) { $redirect_to = sanitize_url( $_GET['redirect_to'] ); } // otherwise, if module has a hub slug use that - else if ( isset( $zbs->modules->$safe_module_name->slugs['hub'] ) ) { + elseif ( isset( $zbs->modules->$safe_module_name->slugs['hub'] ) ) { $redirect_to = jpcrm_esc_link( $zbs->modules->$safe_module_name->slugs['hub'] ); } @@ -135,19 +130,17 @@ public function activate_module_and_redirect() { } else { printf( 'Module %s not found. Error #607', esc_html( $module_name ) ); } - } /** These functions are used to avoid conflicts with old extension names (e.g. WooSync) - * + * * For example: - * + * * - the old Woo extension key is `woosync` * - the new Woo module extension key is `woo-sync` * - the install/load functions for the Woo module use `woo_sync` * - the new Woo module is loaded into `$zbs->modules->woosync` */ - public function get_safe_module_string( $module_name ) { return str_replace( '-', '', $module_name ); } diff --git a/projects/plugins/crm/includes/class-encryption.php b/projects/plugins/crm/includes/class-encryption.php index c236791a38cf..eeb4ad548658 100644 --- a/projects/plugins/crm/includes/class-encryption.php +++ b/projects/plugins/crm/includes/class-encryption.php @@ -1,5 +1,5 @@ -check_cipher_and_fallback(); - } - /* * check if we have the algorhithm we want to use, and fall back if not */ - public function check_cipher_and_fallback(){ + public function check_cipher_and_fallback() { global $zbs; // check if has flipped fallback previously $fallback_blocked = zeroBSCRM_getSetting( 'enc_fallback_blocked' ); - if ( !empty( $fallback_blocked ) ) { + if ( ! empty( $fallback_blocked ) ) { // doesn't even have fallback. Non encrypting!! $this->ready_to_encrypt = false; // error loading encryption - echo zeroBSCRM_UI2_messageHTML( 'warning', __( 'Unable to load encryption method', 'zero-bs-crm' ), sprintf ( __( 'CRM was unable to load the required encryption method (%s). Until this is method is available to your PHP your sensitive data may not be encrypted properly.', 'zero-bs-crm' ), $this->cipher ) ); - + echo zeroBSCRM_UI2_messageHTML( 'warning', __( 'Unable to load encryption method', 'zero-bs-crm' ), sprintf( __( 'CRM was unable to load the required encryption method (%s). Until this is method is available to your PHP your sensitive data may not be encrypted properly.', 'zero-bs-crm' ), $this->cipher ) ); return; @@ -54,7 +51,7 @@ public function check_cipher_and_fallback(){ // check if has flipped fallback previously $fallback_active = zeroBSCRM_getSetting( 'enc_fallback_active' ); - if ( !empty( $fallback_active ) ) { + if ( ! empty( $fallback_active ) ) { // has fallback. Let's use that: $this->cipher = $this->cipher_fallback; @@ -65,69 +62,62 @@ public function check_cipher_and_fallback(){ $available_cipher_methods = openssl_get_cipher_methods(); // check for our method - if ( !in_array( $this->cipher, $available_cipher_methods ) ){ - - // try fallback - if ( in_array( $this->cipher_fallback, $available_cipher_methods ) ){ - - // has fallback. Let's use that: - $this->cipher = $this->cipher_fallback; + if ( ! in_array( $this->cipher, $available_cipher_methods ) ) { - // set option so we get 'stuck' in this mode - $zbs->settings->update( 'enc_fallback_active', $this->cipher ); + // try fallback + if ( in_array( $this->cipher_fallback, $available_cipher_methods ) ) { - } else { + // has fallback. Let's use that: + $this->cipher = $this->cipher_fallback; - // neither method. Present error - $this->ready_to_encrypt = false; + // set option so we get 'stuck' in this mode + $zbs->settings->update( 'enc_fallback_active', $this->cipher ); - // set option so we get 'stuck' in this mode - $zbs->settings->update( 'enc_fallback_blocked', 1 ); + } else { - // error loading encryption - echo zeroBSCRM_UI2_messageHTML( 'warning', __( 'Unable to load encryption method', 'zero-bs-crm' ), sprintf ( __( 'CRM was unable to load the required encryption method (%s). Until this is method is available to your PHP your sensitive data may not be encrypted properly.', 'zero-bs-crm' ), $this->cipher ) ); - - } - - - } + // neither method. Present error + $this->ready_to_encrypt = false; + // set option so we get 'stuck' in this mode + $zbs->settings->update( 'enc_fallback_blocked', 1 ); + // error loading encryption + echo zeroBSCRM_UI2_messageHTML( 'warning', __( 'Unable to load encryption method', 'zero-bs-crm' ), sprintf( __( 'CRM was unable to load the required encryption method (%s). Until this is method is available to your PHP your sensitive data may not be encrypted properly.', 'zero-bs-crm' ), $this->cipher ) ); + } + } } /* * Ready to encrypt? */ - public function ready_to_encrypt(){ + public function ready_to_encrypt() { return $this->ready_to_encrypt; - } /* * Cipher method */ - public function cipher_method(){ + public function cipher_method() { return $this->cipher; - } /* * Encrypts a string */ - public function encrypt( $data, $key = false ){ + public function encrypt( $data, $key = false ) { - if ( $this->ready_to_encrypt ){ + if ( $this->ready_to_encrypt ) { // retrieve encryption key (or default if false) $encryption_key = $this->encryption_key( $key ); // encrypt $iv_length = openssl_cipher_iv_length( $this->cipher ); - $iv = openssl_random_pseudo_bytes( $iv_length ); - $tag = ''; // will be filled by openssl_encrypt + $iv = openssl_random_pseudo_bytes( $iv_length ); + $tag = ''; // will be filled by openssl_encrypt $encrypted = openssl_encrypt( $data, $this->cipher, $encryption_key, OPENSSL_RAW_DATA, $iv, $tag, '', $this->tag_length ); @@ -139,25 +129,24 @@ public function encrypt( $data, $key = false ){ return $data; } - } /* * Decrypts a string */ - public function decrypt( $encrypted_data, $key = false ){ + public function decrypt( $encrypted_data, $key = false ) { - if ( $this->ready_to_encrypt ){ + if ( $this->ready_to_encrypt ) { // retrieve encryption key (or default if false) $encryption_key = $this->encryption_key( $key ); // break up encrypted string into parts - $encrypted = base64_decode( $encrypted_data ); - $iv_len = openssl_cipher_iv_length( $this->cipher ); - $iv = substr( $encrypted, 0, $iv_len ); + $encrypted = base64_decode( $encrypted_data ); + $iv_len = openssl_cipher_iv_length( $this->cipher ); + $iv = substr( $encrypted, 0, $iv_len ); $ciphertext = substr( $encrypted, $iv_len, -$this->tag_length ); - $tag = substr( $encrypted, -$this->tag_length ); + $tag = substr( $encrypted, -$this->tag_length ); return openssl_decrypt( $ciphertext, $this->cipher, $encryption_key, OPENSSL_RAW_DATA, $iv, $tag ); @@ -167,7 +156,6 @@ public function decrypt( $encrypted_data, $key = false ){ return $encrypted_data; } - } /* @@ -175,7 +163,7 @@ public function decrypt( $encrypted_data, $key = false ){ * * @param string $key - a key to make an encryption key for */ - public function get_encryption_key( $key ){ + public function get_encryption_key( $key ) { global $zbs; @@ -186,14 +174,13 @@ public function get_encryption_key( $key ){ $encryption_key = openssl_random_pseudo_bytes( 32 ); $zbs->settings->update( 'enc_' . $key, bin2hex( $encryption_key ) ); - } else { + } else { $encryption_key = hex2bin( $encryption_key ); } return $encryption_key; - } /** @@ -202,7 +189,7 @@ public function get_encryption_key( $key ){ public function get_default_encryption_key() { // cached? - if ( !empty( $this->default_key ) ){ + if ( ! empty( $this->default_key ) ) { return $this->default_key; @@ -215,16 +202,15 @@ public function get_default_encryption_key() { $this->default_key = $default_key; return $default_key; - } /* * Returns an encryption key, or default encryption key if no key passed */ - public function encryption_key( $key ){ + public function encryption_key( $key ) { // retrieve encryption key - if ( !empty( $key ) ){ + if ( ! empty( $key ) ) { // retrieve encryption key for $key return $this->get_encryption_key( $key ); @@ -235,7 +221,6 @@ public function encryption_key( $key ){ return $this->get_default_encryption_key(); } - } /** @@ -248,7 +233,7 @@ public function encryption_key( $key ){ * @return string */ public function get_rand_hex( $bytes = 20 ) { - return bin2hex( openssl_random_pseudo_bytes( (int)$bytes ) ); + return bin2hex( openssl_random_pseudo_bytes( (int) $bytes ) ); } /** diff --git a/projects/plugins/crm/includes/class-endpoint-listener.php b/projects/plugins/crm/includes/class-endpoint-listener.php index f4070bb64aa6..dbe4fb307b35 100644 --- a/projects/plugins/crm/includes/class-endpoint-listener.php +++ b/projects/plugins/crm/includes/class-endpoint-listener.php @@ -3,7 +3,7 @@ * Jetpack CRM Endpoint Listener Class * Provides support for generic verified endpoint call captures * e.g. OAuth return calls of webhooks - * + * * Endpoint example: * https://example.com?jpcrm_listen={hash}&jpcrm_action={action} * https://example.com?jpcrm_listen=1234&jpcrm_action=oauth_gmail @@ -18,7 +18,6 @@ */ class Endpoint_Listener { - /** * Callback url base (url which will be listened for) */ @@ -42,10 +41,8 @@ public function __construct() { // verify & set callback_url $this->establish_callback_url(); - } - /* * Catch listener requests * Fired on load, catches any listener responses inbound @@ -54,104 +51,94 @@ public function __construct() { public function catch_listener_request() { // has hit our hook parameter with a valid key, only needs to fire once. - if ( $this->is_listener_request() && !$this->listened_state ){ + if ( $this->is_listener_request() && ! $this->listened_state ) { // split by action $action = sanitize_text_field( $_GET['jpcrm_action'] ); - if ( $this->legitimate_action( $action ) ){ + if ( $this->legitimate_action( $action ) ) { - // call wp action + // call wp action do_action( 'jpcrm_listener_' . $action ); $this->listened_state = true; } - } - } - /* * Verify and set callback url (frontend) */ - public function establish_callback_url(){ + public function establish_callback_url() { // Set url - $this->callback_url_base = site_url() . '?jpcrm_listen=' . $this->get_listener_key(); - + $this->callback_url_base = site_url() . '?jpcrm_listen=' . $this->get_listener_key(); } /* * Retrieve a callback url with secondary endpoint (action) affixed */ - public function get_callback_url( $action ){ + public function get_callback_url( $action ) { - if ( $this->legitimate_action( $action ) ){ + if ( $this->legitimate_action( $action ) ) { return $this->callback_url_base . '&jpcrm_action=' . $action; } return false; - } /* * Is this request to our listener? */ - public function is_listener_request(){ + public function is_listener_request() { // check for an oauth request & valid key if ( isset( $_GET['jpcrm_listen'] ) && $this->verify_listener_key() ) { - + return true; } return false; - } - /* * Verify listener key against the setting */ - public function verify_listener_key( $key='' ){ + public function verify_listener_key( $key = '' ) { // if key isn't passed, seek for it in _GET - if ( !isset( $key ) || empty( $key ) ){ + if ( ! isset( $key ) || empty( $key ) ) { $potential_key = sanitize_text_field( $_GET['jpcrm_listen'] ); - if ( empty( $potential_key ) ){ + if ( empty( $potential_key ) ) { return false; } else { $key = $potential_key; } - } - if ( $key == $this->get_listener_key() ){ + if ( $key == $this->get_listener_key() ) { return true; } return false; - } - /* * Get listener key */ - public function get_listener_key(){ - + public function get_listener_key() { + global $zbs; // retrieve $key = $zbs->settings->get( 'global_listener_key', false ); // check it - if ( empty( $key ) ){ + if ( empty( $key ) ) { // generate new one return $this->create_listener_key(); @@ -159,15 +146,13 @@ public function get_listener_key(){ } return $key; - } - /* * Create/reset listener key */ - public function create_listener_key(){ - + public function create_listener_key() { + global $zbs; // generate a key @@ -181,16 +166,14 @@ public function create_listener_key(){ // return it return $new_key; - } /* * Get actions */ public function get_actions() { - + return apply_filters( 'jpcrm_listener_actions', $this->actions ); - } /* @@ -198,29 +181,26 @@ public function get_actions() { */ public function add_action( $action ) { - if ( !in_array( $action, $this->actions ) ){ + if ( ! in_array( $action, $this->actions ) ) { $this->actions[] = $action; } return $this->actions; - } - /* * Checks if a action is on the list */ - public function legitimate_action( $action ){ + public function legitimate_action( $action ) { - if ( !empty( $action ) && in_array( $action, $this->get_actions() ) ){ + if ( ! empty( $action ) && in_array( $action, $this->get_actions() ) ) { return true; } return false; - } } diff --git a/projects/plugins/crm/includes/class-missing-settings-exception.php b/projects/plugins/crm/includes/class-missing-settings-exception.php index 8c89fe43110e..791597a4de09 100644 --- a/projects/plugins/crm/includes/class-missing-settings-exception.php +++ b/projects/plugins/crm/includes/class-missing-settings-exception.php @@ -2,7 +2,6 @@ /** * Jetpack CRM Missing Settings Exception Class * Extends Exception to provide additional data. - * */ namespace Automattic\JetpackCRM; diff --git a/projects/plugins/crm/includes/class-oauth-handler.php b/projects/plugins/crm/includes/class-oauth-handler.php index 6857d17b7b58..f300508e4275 100644 --- a/projects/plugins/crm/includes/class-oauth-handler.php +++ b/projects/plugins/crm/includes/class-oauth-handler.php @@ -1,5 +1,5 @@ - array( - 'name' => 'Google Mail', - 'provider' => 'google_mail', // means we'll use 'provider_google_mail()' instead of 'provider_generic()' - 'docs_url' => 'https://kb.jetpackcrm.com/knowledge-base/using-gmail-with-jetpack-crm-mail-delivery-system/#setting-up-gmail-oauth-connection-and-mail-delivery-method', + 'name' => 'Google Mail', + 'provider' => 'google_mail', // means we'll use 'provider_google_mail()' instead of 'provider_generic()' + 'docs_url' => 'https://kb.jetpackcrm.com/knowledge-base/using-gmail-with-jetpack-crm-mail-delivery-system/#setting-up-gmail-oauth-connection-and-mail-delivery-method', // required for refreshing tokens generically: // https://github.com/thephpleague/oauth2-google/blob/main/src/Provider/Google.php#L39 - 'url_authorize' => 'https://accounts.google.com/o/oauth2/v2/auth', - 'url_access_token' => 'https://oauth2.googleapis.com/token', - 'url_resource_owner_details' => 'https://openidconnect.googleapis.com/v1/userinfo', + 'url_authorize' => 'https://accounts.google.com/o/oauth2/v2/auth', + 'url_access_token' => 'https://oauth2.googleapis.com/token', + 'url_resource_owner_details' => 'https://openidconnect.googleapis.com/v1/userinfo', - // required scopes - /* Scopes: https://developers.google.com/gmail/api/auth/scopes + // required scopes + /* + Scopes: https://developers.google.com/gmail/api/auth/scopes https://www.googleapis.com/auth/gmail.compose https://www.googleapis.com/auth/gmail.send Google_Service_Gmail::GMAIL_READONLY */ - 'scopes' => array( 'https://www.googleapis.com/auth/gmail.send' ) - ) + 'scopes' => array( 'https://www.googleapis.com/auth/gmail.send' ), + ), ); - /** * Init */ @@ -67,7 +67,6 @@ public function __construct() { add_action( 'jpcrm_listener_oauth', array( $this, 'catch_oauth_request' ), 10 ); } - /** * Uses package installer to ensure packages are installed */ @@ -77,40 +76,33 @@ public function ensure_packages_installed() { $zbs->load_package_installer(); $zbs->ensure_package_installed( 'oauth_dependencies', 1.0 ); - } - - /** * Return enabled state */ public function enabled() { return $this->enabled; - } - /** * Include league/oauth2-client, (well, in fact, autoload /vendor) * Either: league/oauth2-client * https://oauth2-client.thephpleague.com/usage/ * Or: league/oauth2-google * https://github.com/thephpleague/oauth2-google - * */ - /** * Returns a provider class (typically generated by `provider_generic()`, but allows exceptions, (e.g. `provider_google_mail()`)) */ - public function provider( $provider_key, $args=array() ){ + public function provider( $provider_key, $args = array() ) { // see if we have a unique provider class (e.g. google_mail) $provider_info = $this->get_provider( $provider_key ); - if ( isset( $provider_info['provider'] ) && method_exists( $this, 'provider_' . $provider_info['provider'] ) ){ + if ( isset( $provider_info['provider'] ) && method_exists( $this, 'provider_' . $provider_info['provider'] ) ) { // use custom provider return call_user_func_array( array( $this, 'provider_' . $provider_info['provider'] ), $args ); @@ -121,75 +113,102 @@ public function provider( $provider_key, $args=array() ){ return $this->provider_generic( $args ); } - } - /** * Returns a generic provider instance */ - public function provider_generic( $args=array() ){ + public function provider_generic( $args = array() ) { global $zbs; - // ============ LOAD ARGS ============= - $default_args = array( + // ============ LOAD ARGS ============= + $default_args = array( - 'id' => '', - 'secret' => '', - 'redirect_uri' => '', + 'id' => '', + 'secret' => '', + 'redirect_uri' => '', - 'urlAuthorize' => '', - 'urlAccessToken' => '', - 'urlResourceOwnerDetails' => '' + 'urlAuthorize' => '', + 'urlAccessToken' => '', + 'urlResourceOwnerDetails' => '', - ); foreach ($default_args 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 ( $default_args 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 ============= // make sure our dependencies are installed $this->ensure_packages_installed(); // build provider - return new \League\OAuth2\Client\Provider\GenericProvider([ - 'clientId' => $id, // The client ID assigned to you by the provider - 'clientSecret' => $secret, // The client password assigned to you by the provider - 'redirectUri' => $redirect_uri, // 'https://my.example.com/your-redirect-url/', - 'urlAuthorize' => $urlAuthorize, // 'https://service.example.com/authorize', - 'urlAccessToken' => $urlAccessToken, // 'https://service.example.com/token', - 'urlResourceOwnerDetails' => $urlResourceOwnerDetails //'https://service.example.com/resource' - ]); - + return new \League\OAuth2\Client\Provider\GenericProvider( + array( + 'clientId' => $id, // The client ID assigned to you by the provider + 'clientSecret' => $secret, // The client password assigned to you by the provider + 'redirectUri' => $redirect_uri, // 'https://my.example.com/your-redirect-url/', + 'urlAuthorize' => $urlAuthorize, // 'https://service.example.com/authorize', + 'urlAccessToken' => $urlAccessToken, // 'https://service.example.com/token', + 'urlResourceOwnerDetails' => $urlResourceOwnerDetails, // 'https://service.example.com/resource' + ) + ); } - /** * Returns Google Mail provider instance */ - public function provider_google_mail( $args=array() ){ + public function provider_google_mail( $args = array() ) { - // ============ LOAD ARGS ============= - $default_args = array( + // ============ LOAD ARGS ============= + $default_args = array( - 'id' => '', - 'secret' => '' + 'id' => '', + 'secret' => '', - ); foreach ($default_args 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 ( $default_args 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 ============= // make sure our dependencies are installed $this->ensure_packages_installed(); // args $args = array( - 'clientId' => $id, - 'clientSecret' => $secret, - 'redirectUri' => $this->get_callback_url( 'google_mail' ), - 'accessType' => 'offline', // Required to get a refreshToken - 'scopes' => $this->get_provider_detail( 'google_mail', 'scopes' ) + 'clientId' => $id, + 'clientSecret' => $secret, + 'redirectUri' => $this->get_callback_url( 'google_mail' ), + 'accessType' => 'offline', // Required to get a refreshToken + 'scopes' => $this->get_provider_detail( 'google_mail', 'scopes' ), ); // Hosted Domain, optional; used to restrict access to users on your G Suite/Google Apps for Business accounts - /* We could later expose this via setting, but leaving unrestricted is more useful for now + /* + We could later expose this via setting, but leaving unrestricted is more useful for now $domain = $zbs->get_domain(); if ( $domain ){ $args['hostedDomain'] = $domain; @@ -201,10 +220,8 @@ public function provider_google_mail( $args=array() ){ // return provider return new Google( $args ); - } - /* * Add our listener action to the stack * @@ -214,11 +231,8 @@ public function add_listener_action( $actions = array() ) { $actions[] = 'oauth'; return $actions; - - } - /* * Catch OAuth requests * Fired on load, catches any oauth responses inbound @@ -230,10 +244,10 @@ public function catch_oauth_request() { // split by oauth providers, retrieve provider $provider = sanitize_text_field( $_GET['jpcrm_oauth_provider'] ); - if ( $this->legitimate_provider( $provider ) ){ + if ( $this->legitimate_provider( $provider ) ) { // got auth function? (e.g. `catch_google_mail_authorisation`) - if ( method_exists( $this, 'catch_' . $provider . '_authorisation' ) ){ + if ( method_exists( $this, 'catch_' . $provider . '_authorisation' ) ) { // make sure our dependencies are installed $this->ensure_packages_installed(); @@ -241,24 +255,21 @@ public function catch_oauth_request() { return call_user_func_array( array( $this, 'catch_' . $provider . '_authorisation' ), array() ); } - } - } - /* * Catch Google Mail Authorisation requests * https://github.com/thephpleague/oauth2-google */ - public function catch_google_mail_authorisation(){ + public function catch_google_mail_authorisation() { // at this point the Endpoint_Listener layer has verified the call via `is_listener_request()` - + global $zbs; // require admin - if ( !zeroBSCRM_isZBSAdminOrAdmin() ){ + if ( ! zeroBSCRM_isZBSAdminOrAdmin() ) { return false; @@ -266,16 +277,16 @@ public function catch_google_mail_authorisation(){ // retrieve keys $config = $this->get_provider_config( 'google_mail' ); - if ( !is_array( $config ) || empty( $config['id'] ) || empty( $config['secret'] ) ){ + if ( ! is_array( $config ) || empty( $config['id'] ) || empty( $config['secret'] ) ) { // not yet setup, needs id/secret - $this->display_alert( - 'info', + $this->display_alert( + 'info', __( 'Google API Credentials needed', 'zero-bs-crm' ), '

' . __( 'To authenticate this OAuth connection you\'ll first need to add API credentials.', 'zero-bs-crm' ) . '

' - . '

' . __( 'Add your credentials', 'zero-bs-crm' ) . '

', + . '

' . __( 'Add your credentials', 'zero-bs-crm' ) . '

', + '', '', - '', true // exit ); @@ -287,7 +298,7 @@ public function catch_google_mail_authorisation(){ } // quick check - if ( empty( $google_client_id ) || empty( $google_client_secret ) ){ + if ( empty( $google_client_id ) || empty( $google_client_secret ) ) { return false; } @@ -297,34 +308,39 @@ public function catch_google_mail_authorisation(){ // args $args = array( - 'id' => $google_client_id, - 'secret' => $google_client_secret + 'id' => $google_client_id, + 'secret' => $google_client_secret, ); // retrieve provider $provider = $this->provider_google_mail( $args ); // process - if ( !empty( $_GET['error'] ) ){ + if ( ! empty( $_GET['error'] ) ) { - // Got an error, probably user denied access + // Got an error, probably user denied access $error_string = htmlspecialchars( $_GET['error'], ENT_QUOTES, 'UTF-8' ); - $this->display_alert( - 'warning', + $this->display_alert( + 'warning', sprintf( __( 'Google API Connection Error %s', 'zero-bs-crm' ), '#1' ), '

' . __( 'There was an error connecting to Google:', 'zero-bs-crm' ) . '

' . '

' . $error_string . '

', '', - '', + '', true // exit ); } elseif ( empty( $_GET['code'] ) ) { - // If we don't have an authorization code then redirect to get one - $authorisation_url = $provider->getAuthorizationUrl(['prompt' => 'consent', 'access_type' => 'offline']); - $_SESSION['oauth2state'] = $provider->getState(); - header( 'Location: ' . $authorisation_url ); + // If we don't have an authorization code then redirect to get one + $authorisation_url = $provider->getAuthorizationUrl( + array( + 'prompt' => 'consent', + 'access_type' => 'offline', + ) + ); + $_SESSION['oauth2state'] = $provider->getState(); + header( 'Location: ' . $authorisation_url ); exit( 0 ); } elseif ( empty( $_GET['state'] ) || ( $_GET['state'] !== $_SESSION['oauth2state'] ) ) { @@ -336,125 +352,121 @@ public function catch_google_mail_authorisation(){ try { - // Try to get an access token (using the authorization code grant) - $token = $provider->getAccessToken('authorization_code', [ - 'code' => $_GET['code'] - ]); + // Try to get an access token (using the authorization code grant) + $token = $provider->getAccessToken( + 'authorization_code', + array( + 'code' => $_GET['code'], + ) + ); - // save token (override any existing) - $config['token'] = $token->getToken(); - $config['refresh_token'] = $token->getRefreshToken(); - $config['expires'] = $token->getExpires(); + // save token (override any existing) + $config['token'] = $token->getToken(); + $config['refresh_token'] = $token->getRefreshToken(); + $config['expires'] = $token->getExpires(); - try { + try { - // verify: - if ( !$token->hasExpired() ){ + // verify: + if ( ! $token->hasExpired() ) { - $resource_owner = $provider->getResourceOwner( $token ); - $resource_owner = $resource_owner->toArray(); + $resource_owner = $provider->getResourceOwner( $token ); + $resource_owner = $resource_owner->toArray(); - // if this is an array, we're definitely connected! - if ( is_array( $resource_owner ) && isset( $resource_owner['email']) ){ + // if this is an array, we're definitely connected! + if ( is_array( $resource_owner ) && isset( $resource_owner['email'] ) ) { - // here we can save any meta :) - // (in gmail case, might be useful for mail delivery methods) - if ( !isset( $config['meta'] ) || !is_array( $config['meta'] ) ){ - $config['meta'] = array(); - } + // here we can save any meta :) + // (in gmail case, might be useful for mail delivery methods) + if ( ! isset( $config['meta'] ) || ! is_array( $config['meta'] ) ) { + $config['meta'] = array(); + } - /* Example: - Array + /* + Example: + Array ( - [sub] => 111285058559146358423 - [name] => Woody Hayday - [given_name] => Woody - [family_name] => Hayday - [picture] => https://lh3.googleusercontent.com/a-/AOh14GgBbDQY4COolmrmvq1G4w_NQdirrJfGSPraw8LzEA=s96-c - [email] => woodyhayday@gmail.com - [email_verified] => 1 - [locale] => en-GB + [sub] => 111285058559146358423 + [name] => Woody Hayday + [given_name] => Woody + [family_name] => Hayday + [picture] => https://lh3.googleusercontent.com/a-/AOh14GgBbDQY4COolmrmvq1G4w_NQdirrJfGSPraw8LzEA=s96-c + [email] => woodyhayday@gmail.com + [email_verified] => 1 + [locale] => en-GB ) */ - $fields = array( 'name', 'given_name', 'family_name', 'picture', 'email', 'email_verified', 'locale' ); - foreach ( $fields as $field_key ){ - - if ( isset( $resource_owner[ $field_key ] ) ){ - $config['meta'][ $field_key ] = sanitize_text_field( $resource_owner[ $field_key ] ); - } + $fields = array( 'name', 'given_name', 'family_name', 'picture', 'email', 'email_verified', 'locale' ); + foreach ( $fields as $field_key ) { - } + if ( isset( $resource_owner[ $field_key ] ) ) { + $config['meta'][ $field_key ] = sanitize_text_field( $resource_owner[ $field_key ] ); + } + } + } - } + // Save + $this->update_provider_config( 'google_mail', $config ); - // Save - $this->update_provider_config( 'google_mail', $config ); + // visual output + $account_details = $resource_owner['email']; + if ( isset( $resource_owner['picture'] ) && ! empty( $resource_owner['picture'] ) ) { - // visual output - $account_details = $resource_owner['email']; - if ( isset( $resource_owner['picture'] ) && !empty( $resource_owner['picture'] ) ){ + $account_details = '' . $account_details; - $account_details = '' . $account_details; - - } + } $this->display_alert( - 'info', + 'info', __( 'Google API Connection Complete', 'zero-bs-crm' ), '

' . __( 'You have successfully connected the following Google account to your CRM:', 'zero-bs-crm' ) . '

' . '
' . $account_details . '
' . '

' . __( 'You can now close this window and return to your settings page.', 'zero-bs-crm' ) . '

', '', - '', + '', true, true // refresh on parent close ); + } + } catch ( Exception $e ) { - } - - } catch ( Exception $e ){ - - $this->display_alert( - 'warning', + $this->display_alert( + 'warning', sprintf( __( 'Google API Connection Error %s', 'zero-bs-crm' ), '#2' ), '

' . __( 'There was an error connecting to Google:', 'zero-bs-crm' ) . '

' . '

' . $e->getMessage() . '

', '', - '', + '', true // exit ); } + } catch ( \League\OAuth2\Client\Provider\Exception\IdentityProviderException $e ) { - - } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) { - - $this->display_alert( - 'warning', + $this->display_alert( + 'warning', sprintf( __( 'Google API Connection Error %s', 'zero-bs-crm' ), '#3' ), '

' . __( 'There was an error connecting to Google:', 'zero-bs-crm' ) . '

' . '

' . $e->getMessage() . '

', '', - '', + '', true // exit ); } - } } - /* * Retrieve a callback url with provider affixed */ - public function get_callback_url( $provider ){ + public function get_callback_url( $provider ) { global $zbs; - if ( $this->legitimate_provider( $provider ) ){ + if ( $this->legitimate_provider( $provider ) ) { // load listener if it's not already loaded $zbs->load_listener(); @@ -464,51 +476,46 @@ public function get_callback_url( $provider ){ } return false; - } /* * Checks if a provider is on the list */ - public function legitimate_provider( $provider ){ + public function legitimate_provider( $provider ) { - if ( !empty( $provider ) && in_array( $provider, array_keys( $this->providers ) ) ){ + if ( ! empty( $provider ) && in_array( $provider, array_keys( $this->providers ) ) ) { return true; } return false; - } /* * Retrieves a provider detail, (e.g. google's 'url_authorize') */ - public function get_provider_detail( $provider, $attribute_key ){ + public function get_provider_detail( $provider, $attribute_key ) { - if ( isset( $this->providers[ $provider ] ) && isset( $this->providers[ $provider ][ $attribute_key ] ) ){ + if ( isset( $this->providers[ $provider ] ) && isset( $this->providers[ $provider ][ $attribute_key ] ) ) { return $this->providers[ $provider ][ $attribute_key ]; } return false; - } - /* * Returns provider summary details */ - public function get_provider( $provider ){ + public function get_provider( $provider ) { - if ( isset( $this->providers[ $provider ] ) ){ + if ( isset( $this->providers[ $provider ] ) ) { return $this->providers[ $provider ]; } - } /** @@ -517,21 +524,19 @@ public function get_provider( $provider ){ public function get_providers() { return $this->providers; - } - /* * get config/token for a provider * * @param string $provider_key - e.g. 'google_mail' */ - public function get_provider_config( $provider_key, $return_token_string_only=false, $refresh_token_if_expired=true ){ + public function get_provider_config( $provider_key, $return_token_string_only = false, $refresh_token_if_expired = true ) { global $zbs; // basic check - if ( !$this->legitimate_provider( $provider_key ) ){ + if ( ! $this->legitimate_provider( $provider_key ) ) { return false; } @@ -539,21 +544,21 @@ public function get_provider_config( $provider_key, $return_token_string_only=fa $existing_token_configs = $zbs->settings->get( 'oauth_tokens', false ); // retrieve - if ( is_array( $existing_token_configs ) && isset( $existing_token_configs[ $provider_key ] ) ){ + if ( is_array( $existing_token_configs ) && isset( $existing_token_configs[ $provider_key ] ) ) { // get current - $token_config = $existing_token_configs[ $provider_key ]; - $token_config['expires'] = (int)$token_config['expires']; + $token_config = $existing_token_configs[ $provider_key ]; + $token_config['expires'] = (int) $token_config['expires']; // if expired and $refresh_token_if_expired, regen - if ( $refresh_token_if_expired && !empty( $token_config['token'] ) && isset( $token_config['expires'] ) && $token_config['expires'] < time() ){ + if ( $refresh_token_if_expired && ! empty( $token_config['token'] ) && isset( $token_config['expires'] ) && $token_config['expires'] < time() ) { $this->debug_message( 'Found token which has expired!
' ); // refresh token $refreshed_token_config = $this->refresh_token( $provider_key, $token_config ); - if ( is_array( $refreshed_token_config ) ){ + if ( is_array( $refreshed_token_config ) ) { // success $token_config = $refreshed_token_config; @@ -564,11 +569,10 @@ public function get_provider_config( $provider_key, $return_token_string_only=fa return false; } - } // if only the token itself, return that - if ( $return_token_string_only ){ + if ( $return_token_string_only ) { return $token_config['token']; @@ -581,35 +585,47 @@ public function get_provider_config( $provider_key, $return_token_string_only=fa // no such token return false; - } - /* * Update config/token for a provider * * @param string $provider - e.g. 'google_mail' * @param array $args */ - public function update_provider_config( $provider, $args=array() ){ + public function update_provider_config( $provider, $args = array() ) { global $zbs; - // ============ LOAD ARGS ============= - $default_args = array( + // ============ LOAD ARGS ============= + $default_args = array( - 'id' => '', - 'secret' => '', - 'token' => '', - 'refresh_token' => '', - 'expires' => '', - 'meta' => array() + 'id' => '', + 'secret' => '', + 'token' => '', + 'refresh_token' => '', + 'expires' => '', + 'meta' => array(), - ); foreach ($default_args 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 ( $default_args 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 ============= // basic check - if ( !$this->legitimate_provider( $provider ) ){ + if ( ! $this->legitimate_provider( $provider ) ) { return false; } @@ -617,7 +633,7 @@ public function update_provider_config( $provider, $args=array() ){ $existing_token_configs = $zbs->settings->get( 'oauth_tokens', false ); // check is an array - if ( !is_array( $existing_token_configs ) ) { + if ( ! is_array( $existing_token_configs ) ) { $existing_token_configs = array(); } @@ -625,33 +641,31 @@ public function update_provider_config( $provider, $args=array() ){ $existing_token_configs[ $provider ] = array( // credentials - 'id' => $id, - 'secret' => $secret, + 'id' => $id, + 'secret' => $secret, // token - 'token' => $token, - 'expires' => $expires, - 'refresh_token' => $refresh_token, - 'last_updated_by' => zeroBSCRM_user(), - 'last_updated' => time(), + 'token' => $token, + 'expires' => $expires, + 'refresh_token' => $refresh_token, + 'last_updated_by' => zeroBSCRM_user(), + 'last_updated' => time(), // optional, per provider extras - 'meta' => $meta + 'meta' => $meta, ); // update $zbs->settings->update( 'oauth_tokens', $existing_token_configs ); - } - /* * Delete config/token for a provider * * @param string $provider - e.g. 'google_mail' */ - public function delete_provider_config( $provider ){ + public function delete_provider_config( $provider ) { global $zbs; @@ -659,23 +673,21 @@ public function delete_provider_config( $provider ){ $existing_token_configs = $zbs->settings->get( 'oauth_tokens', false ); // if exists - if ( isset( $existing_token_configs[ $provider ] ) ){ - + if ( isset( $existing_token_configs[ $provider ] ) ) { + // direct unset unset( $existing_token_configs[ $provider ] ); // update $zbs->settings->update( 'oauth_tokens', $existing_token_configs ); - + return true; } return false; - } - /* * Refreshes a user token and returns * @@ -684,10 +696,10 @@ public function delete_provider_config( $provider ){ * * @return array - updated token config */ - public function refresh_token( $provider_key, $provider_config=false ){ + public function refresh_token( $provider_key, $provider_config = false ) { // if no config, load it - if ( !is_array( $provider_config ) ){ + if ( ! is_array( $provider_config ) ) { // note false for third parameter `refresh_token_if_expired` - this is to avoid an infinite loop $provider_config = $this->get_provider_config( $provider_key, false, false ); @@ -695,7 +707,7 @@ public function refresh_token( $provider_key, $provider_config=false ){ } // got refresh token? - if ( !isset( $provider_config['refresh_token'] ) || empty( $provider_config['refresh_token'] ) ){ + if ( ! isset( $provider_config['refresh_token'] ) || empty( $provider_config['refresh_token'] ) ) { return false; @@ -705,29 +717,26 @@ public function refresh_token( $provider_key, $provider_config=false ){ $this->ensure_packages_installed(); // if we have a specific function for this provider, defer to that: - if ( method_exists( $this, 'refresh_token_' . $provider_key ) ){ + if ( method_exists( $this, 'refresh_token_' . $provider_key ) ) { return call_user_func_array( array( $this, 'refresh_token_' . $provider_key ), array( $provider_config ) ); } // otherwise, generic... - + $this->debug_message( 'Refreshing access token...' ); // build args $args = array( + 'id' => $provider_config['id'], + 'secret' => $provider_config['secret'], + 'redirect_uri' => $this->get_callback_url( $provider_key ), - 'id' => $provider_config['id'], - 'secret' => $provider_config['secret'], - 'redirect_uri' => $this->get_callback_url( $provider_key ), - - - 'urlAuthorize' => $this->get_provider_detail( $provider_key, 'url_authorize' ), - 'urlAccessToken' => $this->get_provider_detail( $provider_key, 'url_access_token' ), - 'urlResourceOwnerDetails' => $this->get_provider_detail( $provider_key, 'url_resource_owner_details' ) - + 'urlAuthorize' => $this->get_provider_detail( $provider_key, 'url_authorize' ), + 'urlAccessToken' => $this->get_provider_detail( $provider_key, 'url_access_token' ), + 'urlResourceOwnerDetails' => $this->get_provider_detail( $provider_key, 'url_resource_owner_details' ), ); @@ -738,62 +747,60 @@ public function refresh_token( $provider_key, $provider_config=false ){ // generate new token (generic) // https://oauth2-client.thephpleague.com/usage/#refreshing-a-token - $new_token = $provider->getAccessToken('refresh_token', [ - 'refresh_token' => $provider_config['refresh_token'] - ]); + $new_token = $provider->getAccessToken( + 'refresh_token', + array( + 'refresh_token' => $provider_config['refresh_token'], + ) + ); // success? - if ( !empty( $new_token->getToken() ) ){ + if ( ! empty( $new_token->getToken() ) ) { $this->debug_message( 'Success!' ); $new_refresh_token = $new_token->getRefreshToken(); - + // when a new refresh token isn't set, keep the old one - if ( empty( $new_refresh_token ) ){ + if ( empty( $new_refresh_token ) ) { $new_refresh_token = $provider_config['refresh_token']; } // save it - $config = $this->get_provider_config( $provider_key, false, false ); - $config['token'] = $new_token->getToken(); - $config['refresh_token'] = $new_refresh_token; - $config['expires'] = $new_token->getExpires(); - + $config = $this->get_provider_config( $provider_key, false, false ); + $config['token'] = $new_token->getToken(); + $config['refresh_token'] = $new_refresh_token; + $config['expires'] = $new_token->getExpires(); + $this->update_provider_config( $provider_key, $config ); // return it return $config; } - - - } catch ( \League\OAuth2\Client\Provider\Exception\IdentityProviderException $e ){ + } catch ( \League\OAuth2\Client\Provider\Exception\IdentityProviderException $e ) { $this->debug_message( 'Error refreshing token: ' . $e->getMessage() ); - switch ( $e->getMessage() ){ + switch ( $e->getMessage() ) { case 'invalid_request': default: - // Something wrong with the request $this->debug_message( '
' . print_r( $e->getResponseBody(), 1 ) . '
' ); // clear tokens - $config = $this->get_provider_config( $provider_key, false, false ); - $config['token'] = ''; - $config['expires'] = ''; - $config['refresh_token'] = ''; + $config = $this->get_provider_config( $provider_key, false, false ); + $config['token'] = ''; + $config['expires'] = ''; + $config['refresh_token'] = ''; $this->update_provider_config( $provider_key, $config ); break; } - } return false; - } /* @@ -803,10 +810,10 @@ public function refresh_token( $provider_key, $provider_config=false ){ * * @return array - updated token config */ - public function refresh_token_google_mail( $provider_config=false ){ + public function refresh_token_google_mail( $provider_config = false ) { // if no config, load it - if ( !is_array( $provider_config ) ){ + if ( ! is_array( $provider_config ) ) { // note false for third parameter `refresh_token_if_expired` - this is to avoid an infinite loop $provider_config = $this->get_provider_config( 'google_mail', false, false ); @@ -814,7 +821,7 @@ public function refresh_token_google_mail( $provider_config=false ){ } // got refresh token? - if ( !isset( $provider_config['refresh_token'] ) || empty( $provider_config['refresh_token'] ) ){ + if ( ! isset( $provider_config['refresh_token'] ) || empty( $provider_config['refresh_token'] ) ) { return false; @@ -826,10 +833,10 @@ public function refresh_token_google_mail( $provider_config=false ){ // build arguments $args = array( - 'id' => $provider_config['id'], - 'secret' => $provider_config['secret'] + 'id' => $provider_config['id'], + 'secret' => $provider_config['secret'], - ); + ); // retrieve provider $provider = $this->provider_google_mail( $args ); @@ -841,46 +848,43 @@ public function refresh_token_google_mail( $provider_config=false ){ try { - $new_token = $provider->getAccessToken( $grant, [ 'refresh_token' => $provider_config['refresh_token'] ] ); + $new_token = $provider->getAccessToken( $grant, array( 'refresh_token' => $provider_config['refresh_token'] ) ); $new_refresh_token = $new_token->getRefreshToken(); // when a new refresh token isn't set, keep the old one - if ( empty( $new_refresh_token ) ){ + if ( empty( $new_refresh_token ) ) { $new_refresh_token = $provider_config['refresh_token']; } - $this->debug_message( 'Success!' ); // save it - $config = $this->get_provider_config( 'google_mail', false, false ); + $config = $this->get_provider_config( 'google_mail', false, false ); $config['token'] = $new_token->getToken(); - $config['refresh_token'] = $new_refresh_token; + $config['refresh_token'] = $new_refresh_token; $config['expires'] = $new_token->getExpires(); - + $this->update_provider_config( 'google_mail', $config ); return $config; - } catch ( \League\OAuth2\Client\Provider\Exception\IdentityProviderException $e ){ + } catch ( \League\OAuth2\Client\Provider\Exception\IdentityProviderException $e ) { $this->debug_message( 'Error refreshing Google token: ' . $e->getMessage() ); $this->debug_message( '
' . print_r( $e->getResponseBody(), 1 ) . '
' ); // clear expired/faulty token - $config = $this->get_provider_config( 'google_mail', false, false ); - $config['token'] = ''; - $config['expires'] = ''; - $config['refresh_token'] = ''; + $config = $this->get_provider_config( 'google_mail', false, false ); + $config['token'] = ''; + $config['expires'] = ''; + $config['refresh_token'] = ''; $this->update_provider_config( 'google_mail', $config ); - } + } return false; - } - /* * Returns a connection status (bool) for provider from a provider key or config * Note: Could be hardened by using oauth to re-verify valid token @@ -888,123 +892,111 @@ public function refresh_token_google_mail( $provider_config=false ){ * @param string $provider - e.g. 'google_mail' * @param array|bool $provider_config - if passed, validity of config is checked */ - public function connection_status( $provider, $provider_config=false ){ + public function connection_status( $provider, $provider_config = false ) { // load if not provided - if ( !is_array( $provider_config ) ){ - $provider_config = $this->get_provider_config( $provider ); - } - - // got config? - if ( is_array( $provider_config ) && !empty( $provider_config['id'] ) && !empty( $provider_config['secret'] ) ){ - - if ( - isset( $provider_config['refresh_token'] ) && !empty( $provider_config['refresh_token'] ) - && - isset( $provider_config['expires'] ) && !empty( $provider_config['expires'] ) - ){ + if ( ! is_array( $provider_config ) ) { + $provider_config = $this->get_provider_config( $provider ); + } - return true; + // got config? + if ( is_array( $provider_config ) && ! empty( $provider_config['id'] ) && ! empty( $provider_config['secret'] ) ) { - } + if ( + isset( $provider_config['refresh_token'] ) && ! empty( $provider_config['refresh_token'] ) + && + isset( $provider_config['expires'] ) && ! empty( $provider_config['expires'] ) + ) { - } + return true; - return false; + } + } + return false; } - /* * Returns a connection status string for provider * * @param string $provider - e.g. 'google_mail' * @param bool $shorthand - if true will return 'connected' instead of longform html status */ - public function connection_status_string( $provider, $shorthand=false ){ - - $status = __( 'Not yet configured', 'zero-bs-crm' ); - $short_status = 'no-config'; - - $provider_config = $this->get_provider_config( $provider ); - - // got config? - if ( is_array( $provider_config ) && !empty( $provider_config['id'] ) && !empty( $provider_config['secret'] ) ){ - - $status = __( 'Not yet connected', 'zero-bs-crm' ); - $short_status = 'config-no-connect'; - - if ( - isset( $provider_config['refresh_token'] ) && !empty( $provider_config['refresh_token'] ) - && - isset( $provider_config['expires'] ) && !empty( $provider_config['expires'] ) - ){ - - $short_status = 'seems-connected'; + public function connection_status_string( $provider, $shorthand = false ) { - // some providers can give specific user info to enrich the status string: - switch ( $provider ){ + $status = __( 'Not yet configured', 'zero-bs-crm' ); + $short_status = 'no-config'; - case 'google_mail': + $provider_config = $this->get_provider_config( $provider ); - $username = __( 'Generic User', 'zero-bs-crm' ); - if ( isset( $provider_config['meta'] ) && is_array( $provider_config['meta'] ) ){ + // got config? + if ( is_array( $provider_config ) && ! empty( $provider_config['id'] ) && ! empty( $provider_config['secret'] ) ) { - if ( isset( $provider_config['meta']['name'] ) ){ + $status = __( 'Not yet connected', 'zero-bs-crm' ); + $short_status = 'config-no-connect'; - $username = $provider_config['meta']['name']; + if ( + isset( $provider_config['refresh_token'] ) && ! empty( $provider_config['refresh_token'] ) + && + isset( $provider_config['expires'] ) && ! empty( $provider_config['expires'] ) + ) { - } + $short_status = 'seems-connected'; - if ( isset( $provider_config['meta']['email'] ) ){ + // some providers can give specific user info to enrich the status string: + switch ( $provider ) { - if ( !empty( $username ) ){ - $username .= ' '; - } + case 'google_mail': + $username = __( 'Generic User', 'zero-bs-crm' ); + if ( isset( $provider_config['meta'] ) && is_array( $provider_config['meta'] ) ) { - $username .= '(' . $provider_config['meta']['email'] . ')'; + if ( isset( $provider_config['meta']['name'] ) ) { - } + $username = $provider_config['meta']['name']; + } - } + if ( isset( $provider_config['meta']['email'] ) ) { + if ( ! empty( $username ) ) { + $username .= ' '; + } - $status = '' . sprintf( __( 'Connected as %s', 'zero-bs-crm' ), $username ) . ''; + $username .= '(' . $provider_config['meta']['email'] . ')'; - break; + } + } - default: + $status = '' . sprintf( __( 'Connected as %s', 'zero-bs-crm' ), $username ) . ''; - $status = '' . __( 'Connected', 'zero-bs-crm' ) . ''; + break; - break; + default: + $status = '' . __( 'Connected', 'zero-bs-crm' ) . ''; - } + break; - } - - } + } + } + } - if ( $shorthand ){ - - return $short_status; + if ( $shorthand ) { - } + return $short_status; - return $status; + } + return $status; } - /* * Wrapper for outputting messages, abstracted in case we want to phase into a stack system * There are surely better ways... */ - private function display_alert( $msg_class='', $msg_header='', $msg_html='', $icon_class='', $id='', $singular=false, $refresh_parent = false ){ + private function display_alert( $msg_class = '', $msg_header = '', $msg_html = '', $icon_class = '', $id = '', $singular = false, $refresh_parent = false ) { // if $singular we're just showing the error as a single page (as used in OAuth flow) - if ( $singular ){ + if ( $singular ) { ?> @@ -1012,12 +1004,12 @@ private function display_alert( $msg_class='', $msg_header='', $msg_html='', $ic
+
+ debug ){ + if ( $this->debug ) { echo $message; } - } /** - * Returns an authorized Google API client. - * - * @param string $provider_key - key of OAuth provider to use - * - * @return Client the authorized client object - */ + * Returns an authorized Google API client. + * + * @param string $provider_key - key of OAuth provider to use + * + * @return Client the authorized client object + */ // adapted from class-v3-zerobscrm-googlecontact.php - function get_google_client( $provider_key ){ + function get_google_client( $provider_key ) { // make sure our dependencies are installed $this->ensure_packages_installed(); @@ -1079,14 +1071,14 @@ function get_google_client( $provider_key ){ if ( is_array( $provider_config ) && ! empty( $provider_config['token'] ) ) { - //modified from: https://developers.google.com/people/quickstart/php since we will always be getting 'offline' access so does not need to re-ask user + // modified from: https://developers.google.com/people/quickstart/php since we will always be getting 'offline' access so does not need to re-ask user $client = new \Google_Client(); - $client->setAccessType('offline'); + $client->setAccessType( 'offline' ); $client->setClientId( $provider_config['id'] ); $client->setClientSecret( $provider_config['secret'] ); $client->setAccessToken( $provider_config['token'] ); - $client->setScopes('https://www.googleapis.com/auth/gmail.send'); + $client->setScopes( 'https://www.googleapis.com/auth/gmail.send' ); return $client; diff --git a/projects/plugins/crm/includes/class-package-installer.php b/projects/plugins/crm/includes/class-package-installer.php index e4acdcc607c9..cab67c83be71 100644 --- a/projects/plugins/crm/includes/class-package-installer.php +++ b/projects/plugins/crm/includes/class-package-installer.php @@ -1,5 +1,5 @@ -packages; // if with install status, cycle through and check those - if ( $with_install_status ){ + if ( $with_install_status ) { $return = array(); - foreach ( $packages as $package_key => $package_info ){ + foreach ( $packages as $package_key => $package_info ) { - $return[ $package_key ] = $package_info; + $return[ $package_key ] = $package_info; $return[ $package_key ]['installed'] = $this->get_package_install_info( $package_key ); // check for failed attempts @@ -104,19 +103,17 @@ public function list_all_available_packages( $with_install_status = false ){ } return $packages; - } - /* * Returns info array on package * * @param string $package_key - a slug for a particular package * */ - public function get_package_info( $package_key = '' ){ + public function get_package_info( $package_key = '' ) { - if ( isset( $this->packages[ $package_key ] ) ){ + if ( isset( $this->packages[ $package_key ] ) ) { $package = $this->packages[ $package_key ]; @@ -131,28 +128,27 @@ public function get_package_info( $package_key = '' ){ } return false; - } - /* * Returns installed package info from package's version_info.json file * * @param string $package_key - a slug for a particular package * */ - public function get_package_install_info( $package_key = '' ){ + public function get_package_install_info( $package_key = '' ) { // retrieve version_info.json file and load info $package_version_info_file = $this->package_dir . $package_key . '/version_info.json'; - if ( file_exists( $package_version_info_file ) ){ + if ( file_exists( $package_version_info_file ) ) { - /* Example version_info.json file: + /* + Example version_info.json file: { - "key": "my_package_key", - "version": "1.0" + "key": "my_package_key", + "version": "1.0" } */ @@ -162,7 +158,6 @@ public function get_package_install_info( $package_key = '' ){ } return false; - } /* @@ -172,10 +167,9 @@ public function get_package_install_info( $package_key = '' ){ * * @returns bool(ish) */ - public function package_is_available( $package_key = '' ){ + public function package_is_available( $package_key = '' ) { return ( $this->get_package_info( $package_key ) ? true : false ); // package doesn't exist on CDN or no connection - } /* @@ -185,18 +179,18 @@ public function package_is_available( $package_key = '' ){ * @param float $min_version - if > 0, installed version is compared and returns true only if min version met * */ - public function package_is_installed( $package_key = '', $min_version = 0 ){ + public function package_is_installed( $package_key = '', $min_version = 0 ) { // retrieve installed version data if available $installed_info = $this->get_package_install_info( $package_key ); - if ( !is_array( $installed_info ) ){ - + if ( ! is_array( $installed_info ) ) { + return false; } else { // check min version - if ( $min_version > 0 ){ + if ( $min_version > 0 ) { $local_version = $installed_info['version']; if ( version_compare( $local_version, $min_version, '>=' ) ) { @@ -205,20 +199,17 @@ public function package_is_installed( $package_key = '', $min_version = 0 ){ return true; } - } else { // no min version check, but does seem to be installed return true; } - } // +- check extraction endpoint (e.g. are files actually there?) return false; // package doesn't exist or isn't installed - } /* @@ -228,9 +219,9 @@ public function package_is_installed( $package_key = '', $min_version = 0 ){ * @param float $min_version - if > 0, installed version is compared and returns true only if min version met * */ - public function ensure_package_is_installed( $package_key = '', $min_version = 0 ){ + public function ensure_package_is_installed( $package_key = '', $min_version = 0 ) { - if ( !$this->package_is_installed( $package_key, $min_version ) ){ + if ( ! $this->package_is_installed( $package_key, $min_version ) ) { // not installed, try to install/update(reinstall) it return $this->retrieve_and_install_package( $package_key, true ); @@ -244,41 +235,38 @@ public function ensure_package_is_installed( $package_key = '', $min_version = 0 } return true; - } - /* * Retrieves a package zip from our CDN and installs it locally */ - public function retrieve_and_install_package( $package_key = '', $force_reinstall = false){ + public function retrieve_and_install_package( $package_key = '', $force_reinstall = false ) { global $zbs; // package exists? - if ( !$this->package_is_available( $package_key) ){ + if ( ! $this->package_is_available( $package_key ) ) { return false; } // package already installed? - if ( $this->package_is_installed( $package_key ) && !$force_reinstall ){ + if ( $this->package_is_installed( $package_key ) && ! $force_reinstall ) { return true; } // failed already 3 times? - if ( $this->get_fail_counter( $package_key ) >= 3 ){ + if ( $this->get_fail_counter( $package_key ) >= 3 ) { // Add error msg - zeroBSCRM_notifyme_insert_notification( get_current_user_id(), -999, -1, 'package.installer.fail_count_over', $package_key ); + zeroBSCRM_notifyme_insert_notification( get_current_user_id(), -999, -1, 'package.installer.fail_count_over', $package_key ); return false; } - // here we set a failsafe which sets an option value such that if this install does not complete // ... we'll know the package install failed (e.g. page timeout shorter than download/unzip time) // ... that way we can avoid retrying 50000 times. @@ -286,22 +274,22 @@ public function retrieve_and_install_package( $package_key = '', $force_reinstal // Retrieve & install the package $package_info = $this->get_package_info( $package_key ); - $installed = false; + $installed = false; // Directories $working_dir = $this->package_dir; - if ( !file_exists( $working_dir ) ){ + if ( ! file_exists( $working_dir ) ) { wp_mkdir_p( $working_dir ); jpcrm_create_and_secure_dir_from_external_access( $working_dir, true ); } $target_dir = $package_info['target_dir']; - if ( !file_exists( $target_dir ) ) { + if ( ! file_exists( $target_dir ) ) { wp_mkdir_p( $target_dir ); jpcrm_create_and_secure_dir_from_external_access( $target_dir, true ); } // did that work? - if ( !file_exists( $target_dir ) || !file_exists( $working_dir ) ) { + if ( ! file_exists( $target_dir ) || ! file_exists( $working_dir ) ) { // error creating directories // Add admin notification @@ -316,38 +304,37 @@ public function retrieve_and_install_package( $package_key = '', $force_reinstal $source_file_name = $package_key . '.zip'; // Attempt to download and install - if ( file_exists( $target_dir ) && file_exists( $working_dir ) ){ + if ( file_exists( $target_dir ) && file_exists( $working_dir ) ) { // if force reinstall, clear out previous directory contents - if ( $this->package_is_installed( $package_key ) && $force_reinstall ){ + if ( $this->package_is_installed( $package_key ) && $force_reinstall ) { // empty it out! jpcrm_delete_files_from_directory( $target_dir ); } - // Retrieve package + // Retrieve package $libs = zeroBSCRM_retrieveFile( $zbs->urls['extdlpackages'] . $source_file_name, $working_dir . $source_file_name, array( 'timeout' => 30 ) ); // Process package - if ( file_exists( $working_dir . $source_file_name ) ){ + if ( file_exists( $working_dir . $source_file_name ) ) { - switch ( $package_info['install_method'] ){ + switch ( $package_info['install_method'] ) { // expand a zipped package case 'unzip': - // Expand $expanded = zeroBSCRM_expandArchive( $working_dir . $source_file_name, $target_dir ); - if ( $expanded ){ + if ( $expanded ) { // Check success? - if ( !zeroBSCRM_is_dir_empty( $target_dir ) ){ + if ( ! zeroBSCRM_is_dir_empty( $target_dir ) ) { // appears to have worked, tidy up: - if ( file_exists( $working_dir . $source_file_name ) ){ - unlink( $working_dir . $source_file_name ); + if ( file_exists( $working_dir . $source_file_name ) ) { + unlink( $working_dir . $source_file_name ); } $installed = true; @@ -360,12 +347,11 @@ public function retrieve_and_install_package( $package_key = '', $force_reinstal return false; } - } else { // failed to open the .zip, remove it - if ( file_exists( $working_dir . $source_file_name ) ){ - unlink( $working_dir . $source_file_name ); + if ( file_exists( $working_dir . $source_file_name ) ) { + unlink( $working_dir . $source_file_name ); } // Add admin notification @@ -379,22 +365,20 @@ public function retrieve_and_install_package( $package_key = '', $force_reinstal // 1 file package installs, copy to target location default: - // TBD, add when we need this. break; } - // if successfully installed, do any follow-on tasks - if ( $installed ){ + if ( $installed ) { // Success. Reset fail counter $this->clear_fail_counter( $package_key ); // if the $package_info has ['post_install_call'] set, call that - if ( isset( $package_info['post_install_call'] ) && function_exists( $package_info['post_install_call'] ) ){ + if ( isset( $package_info['post_install_call'] ) && function_exists( $package_info['post_install_call'] ) ) { call_user_func( $package_info['post_install_call'], $package_info ); @@ -403,15 +387,12 @@ public function retrieve_and_install_package( $package_key = '', $force_reinstal return true; } - } else { // Add error msg zeroBSCRM_notifyme_insert_notification( get_current_user_id(), -999, -1, 'package.installer.dl_error', $package_info['title'] . ' (' . $package_key . ')' ); } - - } else { // Add error msg @@ -420,42 +401,34 @@ public function retrieve_and_install_package( $package_key = '', $force_reinstal } return false; - - } - /* * Gets a package fail counter option value */ - private function get_fail_counter( $package_key = ''){ - - return (int)get_option( 'jpcrm_package_fail_' . $package_key, 0 ); + private function get_fail_counter( $package_key = '' ) { + return (int) get_option( 'jpcrm_package_fail_' . $package_key, 0 ); } - /* * Adds a tick to a package fail counter option ( to track failed installs ) */ - private function increment_fail_counter( $package_key = ''){ + private function increment_fail_counter( $package_key = '' ) { // here we set a failsafe which sets an option value such that if this install does not complete // ... we'll know the package install failed (e.g. page timeout shorter than download/unzip time) // ... that way we can avoid retrying 50000 times. $existing_fails = $this->get_fail_counter( $package_key ); update_option( 'jpcrm_package_fail_' . $package_key, $existing_fails + 1, false ); - } - /* * Resets fail counter for a package */ - private function clear_fail_counter( $package_key = ''){ + private function clear_fail_counter( $package_key = '' ) { // simple. delete_option( 'jpcrm_package_fail_' . $package_key ); - } } diff --git a/projects/plugins/crm/includes/class-segment-condition-exception.php b/projects/plugins/crm/includes/class-segment-condition-exception.php index 9455e8c5d69a..228f8bd79d7c 100644 --- a/projects/plugins/crm/includes/class-segment-condition-exception.php +++ b/projects/plugins/crm/includes/class-segment-condition-exception.php @@ -2,7 +2,6 @@ /** * Jetpack CRM Segment Condition Exception Class * Extends Exception to provide additional data. - * */ namespace Automattic\JetpackCRM; diff --git a/projects/plugins/crm/includes/class-segment-condition.php b/projects/plugins/crm/includes/class-segment-condition.php index f4ddcdcf5f49..4113cd402a3e 100644 --- a/projects/plugins/crm/includes/class-segment-condition.php +++ b/projects/plugins/crm/includes/class-segment-condition.php @@ -1,5 +1,5 @@ -init( $constructionArgs ); - - } - - public function init( $constructionArgs = array() ){ + public $key = false; + public $condition = false; + public $superseded_keys = array(); - global $zbs; + // killswitch + private $addFilters = true; - if ( $this->addFilters && $this->key !== false && is_array( $this->condition ) ){ + /** + * Jetpack CRM Segment Argument Constructor. + */ + public function __construct( $constructionArgs = array() ) { - // __ name, category, description etc. - if ( isset( $this->condition['name'] ) ) $this->condition['name'] = __( $this->condition['name'], 'zero-bs-crm' ); - if ( isset( $this->condition['category'] ) ) $this->condition['category'] = __( $this->condition['category'], 'zero-bs-crm' ); - if ( isset( $this->condition['description'] ) ) $this->condition['description'] = __( $this->condition['description'], 'zero-bs-crm' ); + // in children we play with the order here (preConstructor) + // so it's separated into an init func + $this->init( $constructionArgs ); + } - // add the condition - add_filter( 'zbs_segment_conditions', array( $this, 'condition' ) ); + public function init( $constructionArgs = array() ) { - // add the query arg builder - add_filter( $zbs->DAL->makeSlug( $this->key ) . '_zbsSegmentArgumentBuild', array( $this, 'conditionArg' ), 10, 3 ); + global $zbs; - // any conditions that this supersedes get filters added too, to ensure backward compatibility (though these should be migrated too) - if ( is_array( $this->superseded_keys ) ){ + if ( $this->addFilters && $this->key !== false && is_array( $this->condition ) ) { - foreach ( $this->superseded_keys as $key ){ + // __ name, category, description etc. + if ( isset( $this->condition['name'] ) ) { + $this->condition['name'] = __( $this->condition['name'], 'zero-bs-crm' ); + } + if ( isset( $this->condition['category'] ) ) { + $this->condition['category'] = __( $this->condition['category'], 'zero-bs-crm' ); + } + if ( isset( $this->condition['description'] ) ) { + $this->condition['description'] = __( $this->condition['description'], 'zero-bs-crm' ); + } - // add filter - add_filter( $key . '_zbsSegmentArgumentBuild', array( $this, 'condition_arg_superseded' ), 10, 3 ); + // add the condition + add_filter( 'zbs_segment_conditions', array( $this, 'condition' ) ); - } + // add the query arg builder + add_filter( $zbs->DAL->makeSlug( $this->key ) . '_zbsSegmentArgumentBuild', array( $this, 'conditionArg' ), 10, 3 ); - } + // any conditions that this supersedes get filters added too, to ensure backward compatibility (though these should be migrated too) + if ( is_array( $this->superseded_keys ) ) { - } + foreach ( $this->superseded_keys as $key ) { - } + // add filter + add_filter( $key . '_zbsSegmentArgumentBuild', array( $this, 'condition_arg_superseded' ), 10, 3 ); - public function condition( $conditions = array() ) { + } + } + } + } - if ( $this->key !== false && is_array( $this->condition ) ){ + public function condition( $conditions = array() ) { - return array_merge( $conditions, array( $this->key => $this->condition ) ); + if ( $this->key !== false && is_array( $this->condition ) ) { - } + return array_merge( $conditions, array( $this->key => $this->condition ) ); - // else don't add - return $conditions; - } + } - // note starting arg is ignored (should not have been called multiple times) - public function conditionArg($startingArg=false,$condition=false,$conditionKeySuffix=false){ + // else don't add + return $conditions; + } - global $zbs,$wpdb,$ZBSCRM_t; + // note starting arg is ignored (should not have been called multiple times) + public function conditionArg( $startingArg = false, $condition = false, $conditionKeySuffix = false ) { - return $startingArg; - } + global $zbs, $wpdb, $ZBSCRM_t; - /* - * This fires when a superseded condition key has been used - * It'll migrate the key in the db then return as `conditionArg()` - */ - public function condition_arg_superseded( $startingArg = false, $condition = false, $conditionKeySuffix = false ){ + return $startingArg; + } - global $zbs; + /* + * This fires when a superseded condition key has been used + * It'll migrate the key in the db then return as `conditionArg()` + */ + public function condition_arg_superseded( $startingArg = false, $condition = false, $conditionKeySuffix = false ) { - // migrate to avoid future reoccurances - $zbs->DAL->segments->migrate_superseded_condition( $condition['type'], $this->key ); + global $zbs; - // return conditionArg as if normal - return $this->conditionArg( $startingArg, $condition, $conditionKeySuffix ); + // migrate to avoid future reoccurances + $zbs->DAL->segments->migrate_superseded_condition( $condition['type'], $this->key ); - } + // return conditionArg as if normal + return $this->conditionArg( $startingArg, $condition, $conditionKeySuffix ); + } } diff --git a/projects/plugins/crm/includes/class-wordpress-user-integration.php b/projects/plugins/crm/includes/class-wordpress-user-integration.php index 4149c2592c49..e4629243337c 100644 --- a/projects/plugins/crm/includes/class-wordpress-user-integration.php +++ b/projects/plugins/crm/includes/class-wordpress-user-integration.php @@ -1,5 +1,5 @@ -init_hooks(); - } /* * Initialise hooks */ - public function init_hooks(){ + public function init_hooks() { add_action( 'profile_update', array( $this, 'wordpress_profile_update' ), 10, 3 ); - } - /* * Catches WordPress user profile updates and updates any related Contacts * Works for all WP users and related systems (e.g. WooSync) @@ -45,21 +42,20 @@ public function init_hooks(){ */ public function wordpress_profile_update( $user_id, $old_user_data, $new_user_data ) { - global $zbs,$wp_query; + global $zbs, $wp_query; // detect whether these changes are coming from Profile page or Woo my account page: $change_via_woo_account = false; // here we use a relatively hacky approach to retrieve the posted page // ... though it seems the best approach - if ( is_object( $wp_query ) && isset( $wp_query->queried_object ) && isset( $wp_query->queried_object->post_content ) ){ + if ( is_object( $wp_query ) && isset( $wp_query->queried_object ) && isset( $wp_query->queried_object->post_content ) ) { if ( str_contains( $wp_query->queried_object->post_content, '[woocommerce_my_account]' ) ) { $change_via_woo_account = true; } - } // This var will be defined as JPCRM_PROFILE_UPDATE_CHANGES, which will allow WooSync's save_my_account_crm_field_changes to sidestep repeating changes @@ -68,40 +64,46 @@ public function wordpress_profile_update( $user_id, $old_user_data, $new_user_da // retrieve id's $old_user_contact_id = false; $new_user_contact_id = false; - $email_conflict = false; - if ( isset( $old_user_data->data->user_email ) ){ + $email_conflict = false; + if ( isset( $old_user_data->data->user_email ) ) { // check if we have contacts with emails - $old_user_contact_id = $zbs->DAL->contacts->getContact( -1, array( + $old_user_contact_id = $zbs->DAL->contacts->getContact( + -1, + array( - 'email' => $old_user_data->data->user_email, - 'onlyID' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) + 'email' => $old_user_data->data->user_email, + 'onlyID' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - )); + ) + ); } - if ( isset( $new_user_data['user_email'] ) ){ + if ( isset( $new_user_data['user_email'] ) ) { - $new_user_contact_id = $zbs->DAL->contacts->getContact( -1, array( + $new_user_contact_id = $zbs->DAL->contacts->getContact( + -1, + array( - 'email' => $new_user_data['user_email'], - 'onlyID' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) + 'email' => $new_user_data['user_email'], + 'onlyID' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), - )); + ) + ); } // Email change (For Client Portal Users & WooSync originated contacts) - if ( $old_user_data->data->user_email != $new_user_data['user_email'] ){ + if ( $old_user_data->data->user_email != $new_user_data['user_email'] ) { // if we had a contact with this users email... - if ( $old_user_contact_id > 0 ){ + if ( $old_user_contact_id > 0 ) { // if we don't already have a contact with this new email (no collision) - if ( !$new_user_contact_id ){ + if ( ! $new_user_contact_id ) { // update contacts email address: $zbs->DAL->contacts->update_contact_email( $old_user_contact_id, $new_user_data['user_email'] ); @@ -110,28 +112,28 @@ public function wordpress_profile_update( $user_id, $old_user_data, $new_user_da $profile_update_changes[] = 'email'; // Add log noting the email change - $note_type = 'contact_changed_details_via_wpprofile'; + $note_type = 'contact_changed_details_via_wpprofile'; $short_description = __( 'Email changed', 'zero-bs-crm' ); - if ( $change_via_woo_account ){ + if ( $change_via_woo_account ) { $note_type = 'contact_changed_details_via_woomyacc'; } - $zbs->DAL->logs->addUpdateLog( array( + $zbs->DAL->logs->addUpdateLog( + array( - 'id' => -1, - 'owner' => -1, - 'data' => array( + 'id' => -1, + 'owner' => -1, + 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $old_user_contact_id, - 'type' => $note_type, // contact_changed_details_via_wpprofile or contact_changed_details_via_woomyacc - 'shortdesc' => $short_description, - 'longdesc' => sprintf( __( 'Contact email changed from `%s` to `%s`', 'zero-bs-crm' ), $old_user_data->data->user_email, $new_user_data['user_email'] ), - - ) + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $old_user_contact_id, + 'type' => $note_type, // contact_changed_details_via_wpprofile or contact_changed_details_via_woomyacc + 'shortdesc' => $short_description, + 'longdesc' => sprintf( __( 'Contact email changed from `%1$s` to `%2$s`', 'zero-bs-crm' ), $old_user_data->data->user_email, $new_user_data['user_email'] ), - )); + ), - + ) + ); } else { @@ -141,145 +143,152 @@ public function wordpress_profile_update( $user_id, $old_user_data, $new_user_da // flag so that we don't also update the new users details below $email_conflict = true; - // Add a log to both contacts. + // Add a log to both contacts. $short_description = __( 'Attempted email Change', 'zero-bs-crm' ); - $zbs->DAL->logs->addUpdateLog( array( + $zbs->DAL->logs->addUpdateLog( + array( - 'id' => -1, - 'owner' => -1, - 'data' => array( + 'id' => -1, + 'owner' => -1, + 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $old_user_contact_id, - 'type' => 'contact_change_details_attempt', - 'shortdesc' => $short_description, - 'longdesc' => sprintf( __( 'There was an attempt to change this contacts email from `%s` to `%s`, unfortunately this was not possible because another contact (#%d) already uses that email address.', 'zero-bs-crm' ), $old_user_data->data->user_email, $new_user_data['user_email'], $new_user_contact_id ), - - ) + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $old_user_contact_id, + 'type' => 'contact_change_details_attempt', + 'shortdesc' => $short_description, + 'longdesc' => sprintf( __( 'There was an attempt to change this contacts email from `%1$s` to `%2$s`, unfortunately this was not possible because another contact (#%3$d) already uses that email address.', 'zero-bs-crm' ), $old_user_data->data->user_email, $new_user_data['user_email'], $new_user_contact_id ), - )); - $zbs->DAL->logs->addUpdateLog( array( + ), - 'id' => -1, - 'owner' => -1, - 'data' => array( + ) + ); + $zbs->DAL->logs->addUpdateLog( + array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $new_user_contact_id, - 'type' => 'contact_change_details_attempt', - 'shortdesc' => $short_description, - 'longdesc' => sprintf( __( 'There was an attempt to change another contact\'s (#%d) email from `%s` to `%s`, this was not possible because this contact already uses that email address.', 'zero-bs-crm' ), $old_user_contact_id, $old_user_data->data->user_email, $new_user_data['user_email'] ), - - ) + 'id' => -1, + 'owner' => -1, + 'data' => array( - )); + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $new_user_contact_id, + 'type' => 'contact_change_details_attempt', + 'shortdesc' => $short_description, + 'longdesc' => sprintf( __( 'There was an attempt to change another contact\'s (#%1$d) email from `%2$s` to `%3$s`, this was not possible because this contact already uses that email address.', 'zero-bs-crm' ), $old_user_contact_id, $old_user_data->data->user_email, $new_user_data['user_email'] ), - } - - } + ), + ) + ); + } + } } - // First and last names are available in $new_user_data but not in old. // Here we brutally updated these, which in some cases may be further updated by `save_my_account_crm_field_changes()` in WooSync // ... if changes posted through Woo My Account, and fname/lname specified as editable fields. // if we have a contact to op, and this isn't a conflicting situation: - if ( isset( $old_user_contact_id ) && $old_user_contact_id > 0 && !$email_conflict ){ + if ( isset( $old_user_contact_id ) && $old_user_contact_id > 0 && ! $email_conflict ) { // discern if changes - $changes = array(); + $changes = array(); $detail_change_description = ''; // retrieve existing - $contact = $zbs->DAL->contacts->getContact( $old_user_contact_id, array( 'withCustomFields' => false, 'fields'=>array( 'zbsc_fname', 'zbsc_lname' ), 'ignoreowner' => true ) ); + $contact = $zbs->DAL->contacts->getContact( + $old_user_contact_id, + array( + 'withCustomFields' => false, + 'fields' => array( 'zbsc_fname', 'zbsc_lname' ), + 'ignoreowner' => true, + ) + ); // first name - if ( isset( $new_user_data['first_name'] ) ){ - + if ( isset( $new_user_data['first_name'] ) ) { + $new_first_name = $new_user_data['first_name']; - if ( $contact['fname'] != $new_first_name ){ - + if ( $contact['fname'] != $new_first_name ) { + // add limitedFields change - $changes[] = array( - 'key' => 'zbsc_fname', - 'val' => $new_first_name, - 'type' => '%s' - ); + $changes[] = array( + 'key' => 'zbsc_fname', + 'val' => $new_first_name, + 'type' => '%s', + ); - // add to log - $detail_change_description .= '
' . sprintf( __( 'First name changed from `%s` to `%s`', 'zero-bs-crm' ), $contact['fname'], $new_first_name ); + // add to log + $detail_change_description .= '
' . sprintf( __( 'First name changed from `%1$s` to `%2$s`', 'zero-bs-crm' ), $contact['fname'], $new_first_name ); // flag so woosync doesn't also update $profile_update_changes[] = 'fname'; } - } // last name - if ( isset( $new_user_data['last_name'] ) ){ - + if ( isset( $new_user_data['last_name'] ) ) { + $new_last_name = $new_user_data['last_name']; - if ( $contact['lname'] != $new_last_name ){ + if ( $contact['lname'] != $new_last_name ) { // add limitedFields change - $changes[] = array( - 'key' => 'zbsc_lname', - 'val' => $new_last_name, - 'type' => '%s' - ); + $changes[] = array( + 'key' => 'zbsc_lname', + 'val' => $new_last_name, + 'type' => '%s', + ); - // add to log - $detail_change_description .= '
' . sprintf( __( 'Last name changed from `%s` to `%s`', 'zero-bs-crm' ), $contact['lname'], $new_last_name ); + // add to log + $detail_change_description .= '
' . sprintf( __( 'Last name changed from `%1$s` to `%2$s`', 'zero-bs-crm' ), $contact['lname'], $new_last_name ); // flag so woosync doesn't also update $profile_update_changes[] = 'lname'; } - } // any changes? - if ( count( $changes ) > 0 ){ + if ( count( $changes ) > 0 ) { // update contact - $zbs->DAL->contacts->addUpdateContact( array( - 'id' => $old_user_contact_id, - 'limitedFields' => $changes - )); + $zbs->DAL->contacts->addUpdateContact( + array( + 'id' => $old_user_contact_id, + 'limitedFields' => $changes, + ) + ); // Add log noting the email change - $note_type = 'contact_changed_details_via_wpprofile'; + $note_type = 'contact_changed_details_via_wpprofile'; $short_description = __( 'Contact name change', 'zero-bs-crm' ); - if ( $change_via_woo_account ){ + if ( $change_via_woo_account ) { $note_type = 'contact_changed_details_via_woomyacc'; } - $zbs->DAL->logs->addUpdateLog( array( + $zbs->DAL->logs->addUpdateLog( + array( - 'id' => -1, - 'owner' => -1, - 'data' => array( + 'id' => -1, + 'owner' => -1, + 'data' => array( - 'objtype' => ZBS_TYPE_CONTACT, - 'objid' => $old_user_contact_id, - 'type' => $note_type, - 'shortdesc' => $short_description, - 'longdesc' => __( 'Contact details changed:', 'zero-bs-crm' ) . $detail_change_description, - - ) + 'objtype' => ZBS_TYPE_CONTACT, + 'objid' => $old_user_contact_id, + 'type' => $note_type, + 'shortdesc' => $short_description, + 'longdesc' => __( 'Contact details changed:', 'zero-bs-crm' ) . $detail_change_description, - )); - } + ), + ) + ); + } } // if posted from woo my account, define any changes so that woosync doesn't repeat them - if ( !defined( 'JPCRM_PROFILE_UPDATE_CHANGES' ) && $change_via_woo_account && count( $profile_update_changes ) > 0 ){ + if ( ! defined( 'JPCRM_PROFILE_UPDATE_CHANGES' ) && $change_via_woo_account && count( $profile_update_changes ) > 0 ) { define( 'JPCRM_PROFILE_UPDATE_CHANGES', $profile_update_changes ); } - } } diff --git a/projects/plugins/crm/includes/jpcrm-dependency-checker.php b/projects/plugins/crm/includes/jpcrm-dependency-checker.php index cd6ff8a41554..f5ce842d6822 100644 --- a/projects/plugins/crm/includes/jpcrm-dependency-checker.php +++ b/projects/plugins/crm/includes/jpcrm-dependency-checker.php @@ -2,10 +2,9 @@ defined( 'ZEROBSCRM_PATH' ) || exit( 0 ); /** - * + * * The JPCRMDependencyChecker class provides various functions that * can be used to verify dependencies for features and extensions - * */ class JPCRM_DependencyChecker { @@ -55,16 +54,18 @@ public function __construct() { * * @return bool */ - public function check_all_reqs( $feature_name='', $core_reqs=array() , $plugin_reqs=array(), $is_silent=false ) { - $meets_core_reqs = $this->check_core_reqs($feature_name, $core_reqs, $is_silent); - $meets_plug_reqs = $this->check_plugin_reqs($feature_name, $plugin_reqs, $is_silent); - - // everything checks out - if ( $meets_core_reqs && $meets_plug_reqs ) return true; + public function check_all_reqs( $feature_name = '', $core_reqs = array(), $plugin_reqs = array(), $is_silent = false ) { + $meets_core_reqs = $this->check_core_reqs( $feature_name, $core_reqs, $is_silent ); + $meets_plug_reqs = $this->check_plugin_reqs( $feature_name, $plugin_reqs, $is_silent ); - // something didn't pass - return false; - } + // everything checks out + if ( $meets_core_reqs && $meets_plug_reqs ) { + return true; + } + + // something didn't pass + return false; + } /** * Checks if feature meets core dependency requirements @@ -76,24 +77,24 @@ public function check_all_reqs( $feature_name='', $core_reqs=array() , $plugin_r * * @return bool */ - public function check_core_reqs( $feature_name='', $args=array(), $is_silent=false ) { - $req_core_ver = !empty( $args['req_core_ver'] ) ? $args['req_core_ver'] : 1e6; //high version number - $is_good_core_ver = version_compare( $this->core_ver, $req_core_ver, '>=' ); - $req_DAL_ver = !empty( $args['req_DAL_ver'] ) ? $args['req_DAL_ver'] : false; - $is_good_DAL_ver = version_compare( $this->dal_ver, $req_DAL_ver, '>=' ); - - // return true if everything checks out - if ( $is_good_core_ver && $is_good_DAL_ver) { - return true; - } - // return false if silent check - elseif ($is_silent) { - return false; - } - - global $zbs; - // otherwise, proceed to trigger an admin notice - $feature_name = !empty( $feature_name ) ? $feature_name : __( 'CRM feature', 'zero-bs-crm' ); + public function check_core_reqs( $feature_name = '', $args = array(), $is_silent = false ) { + $req_core_ver = ! empty( $args['req_core_ver'] ) ? $args['req_core_ver'] : 1e6; // high version number + $is_good_core_ver = version_compare( $this->core_ver, $req_core_ver, '>=' ); + $req_DAL_ver = ! empty( $args['req_DAL_ver'] ) ? $args['req_DAL_ver'] : false; + $is_good_DAL_ver = version_compare( $this->dal_ver, $req_DAL_ver, '>=' ); + + // return true if everything checks out + if ( $is_good_core_ver && $is_good_DAL_ver ) { + return true; + } + // return false if silent check + elseif ( $is_silent ) { + return false; + } + + global $zbs; + // otherwise, proceed to trigger an admin notice + $feature_name = ! empty( $feature_name ) ? $feature_name : __( 'CRM feature', 'zero-bs-crm' ); if ( empty( $this->core_ver ) || empty( $this->dal_ver ) ) { $error_msg = __( 'Your CRM install appears to have issues. Please verify the CRM is fully installed and any notices are properly handled before trying again.', 'zero-bs-crm' ); @@ -101,22 +102,21 @@ public function check_core_reqs( $feature_name='', $args=array(), $is_silent=fal $error_msg = __( 'Your Jetpack CRM install appears to have issues. Please verify the CRM is fully installed and any notices are properly handled before trying again.', 'zero-bs-crm' ); ##/WLREMOVE } elseif ( ! $is_good_core_ver ) { - $error_msg = sprintf( __( '%s requires CRM version %s or greater, but version %s is currently installed. Please update your CRM to use this feature.', 'zero-bs-crm' ), $feature_name, $req_core_ver, $this->core_ver ); - ##WLREMOVE - $error_msg = sprintf( __( '%s requires Jetpack CRM version %s or greater, but version %s is currently installed. Please update Jetpack CRM to use this feature.', 'zero-bs-crm' ), $feature_name, $req_core_ver, $this->core_ver ); - ##/WLREMOVE - } - else if ( !$is_good_DAL_ver ) { - $error_msg = sprintf( __( '%s requires your CRM database to be updated. Please visit your CRM dashboard for more information.', 'zero-bs-crm' ), $feature_name, zeroBSCRM_getAdminURL( $zbs->slugs['dash'] ) ); - } - - $error_fn = function() use( $error_msg ) { - $this->show_dependency_error( $error_msg ); - }; - add_action( 'admin_notices', $error_fn ); - - return false; - } + $error_msg = sprintf( __( '%1$s requires CRM version %2$s or greater, but version %3$s is currently installed. Please update your CRM to use this feature.', 'zero-bs-crm' ), $feature_name, $req_core_ver, $this->core_ver ); + ##WLREMOVE + $error_msg = sprintf( __( '%1$s requires Jetpack CRM version %2$s or greater, but version %3$s is currently installed. Please update Jetpack CRM to use this feature.', 'zero-bs-crm' ), $feature_name, $req_core_ver, $this->core_ver ); + ##/WLREMOVE + } elseif ( ! $is_good_DAL_ver ) { + $error_msg = sprintf( __( '%1$s requires your CRM database to be updated. Please visit your CRM dashboard for more information.', 'zero-bs-crm' ), $feature_name, zeroBSCRM_getAdminURL( $zbs->slugs['dash'] ) ); + } + + $error_fn = function () use ( $error_msg ) { + $this->show_dependency_error( $error_msg ); + }; + add_action( 'admin_notices', $error_fn ); + + return false; + } /** * Checks if a plugin is installed @@ -125,12 +125,12 @@ public function check_core_reqs( $feature_name='', $args=array(), $is_silent=fal * * @return bool */ - private function is_plugin_installed( $slug='' ){ - if ( array_key_exists( $slug, $this->all_plugins ) ) { - return true; - } - return false; - } + private function is_plugin_installed( $slug = '' ) { + if ( array_key_exists( $slug, $this->all_plugins ) ) { + return true; + } + return false; + } /** * Gets plugin version @@ -139,12 +139,12 @@ private function is_plugin_installed( $slug='' ){ * * @return string|bool plugin version or false if slug is not found */ - private function get_plugin_version( $slug='' ) { - if ( $this->is_plugin_installed( $slug ) ) { - return $this->all_plugins[$slug]['Version']; - } - return false; - } + private function get_plugin_version( $slug = '' ) { + if ( $this->is_plugin_installed( $slug ) ) { + return $this->all_plugins[ $slug ]['Version']; + } + return false; + } /** * Checks if feature's plugin dependency requirements are met @@ -157,91 +157,87 @@ private function get_plugin_version( $slug='' ) { * * @return bool */ - public function check_plugin_reqs( $feature_name='', $plugins=array(), $is_silent=false, $error_msg='' ) { - $everything_is_fine = true; - $feature_name = !empty( $feature_name ) ? $feature_name : __( 'CRM feature', 'zero-bs-crm' ); - - // if we don't have an array of arrays (e.g. only one plugin is passed), make one - if ( !isset( $plugins[0] ) ) { - $plugins = array( $plugins ); - } - foreach ( $plugins as $args ) { - $slug = !empty( $args['slug'] ) ? $args['slug'] : ''; - $cur_ver = $this->get_plugin_version( $slug ); - $req_ver = !empty( $args['req_ver'] ) ? $args['req_ver'] : 1e6; //high version number - $is_good_ver = version_compare($cur_ver, $req_ver, '>='); - $is_active = is_plugin_active( $slug ); - - // move to next plugin check if everything checks out - if ( $is_active && $is_good_ver ) { - continue; - } - - $everything_is_fine = false; - - // short-circuit if silent check - if ( $is_silent || ! current_user_can( 'activate_plugins' ) ) { - break; - } - - // otherwise, proceed to trigger an admin notice - $plugin_name = !empty( $args['name'] ) ? $args['name'] : $slug; //use slug if no name - $plugin_link = !empty( $args['link'] ) ? $args['link'] : false; - $is_installed = $this->is_plugin_installed( $slug ); - - if ( empty( $slug ) ) { - $error_msg = __( 'A CRM feature has an unknown missing dependency. Please contact support!' ); - ##WLREMOVE - $error_msg = __( 'A Jetpack CRM feature has an unknown missing dependency. Please contact support!' ); - ##/WLREMOVE - } - else if ( empty( $error_msg ) ) { - if ( !$is_installed ) { - $error_msg = sprintf( __( '%s requires %s version %s or greater. Please install and activate %s to use this feature.', 'zero-bs-crm' ), $feature_name, $plugin_link?''.$plugin_name.'':$plugin_name, $req_ver, $plugin_name ); - } - else if ( $is_installed && !$is_good_ver ) { - $error_msg = sprintf( __( '%s requires %s version %s or greater, but version %s is currently installed. Please update %s to use this feature.', 'zero-bs-crm' ), $feature_name, $plugin_name, $req_ver, $cur_ver, $plugin_name ); - } - else if ( !$is_active ) { - $error_msg = sprintf( __( '%s requires the %s plugin to be active. Please activate %s to use this feature.', 'zero-bs-crm' ), $feature_name, $plugin_name, $plugin_name ); - ##WLREMOVE - if ( !empty( $args['kb_link'] ) ) { - $error_msg .= '

'; - $error_msg .= sprintf( __( 'To learn more about how this feature works, click here.', 'zero-bs-crm' ), $args['kb_link'] ); - } - ##/WLREMOVE - } - } - - $error_fn = function() use( $error_msg ) { - $this->show_dependency_error( $error_msg ); - }; - add_action( 'admin_notices', $error_fn ); - } - return $everything_is_fine; - } + public function check_plugin_reqs( $feature_name = '', $plugins = array(), $is_silent = false, $error_msg = '' ) { + $everything_is_fine = true; + $feature_name = ! empty( $feature_name ) ? $feature_name : __( 'CRM feature', 'zero-bs-crm' ); + + // if we don't have an array of arrays (e.g. only one plugin is passed), make one + if ( ! isset( $plugins[0] ) ) { + $plugins = array( $plugins ); + } + foreach ( $plugins as $args ) { + $slug = ! empty( $args['slug'] ) ? $args['slug'] : ''; + $cur_ver = $this->get_plugin_version( $slug ); + $req_ver = ! empty( $args['req_ver'] ) ? $args['req_ver'] : 1e6; // high version number + $is_good_ver = version_compare( $cur_ver, $req_ver, '>=' ); + $is_active = is_plugin_active( $slug ); + + // move to next plugin check if everything checks out + if ( $is_active && $is_good_ver ) { + continue; + } + + $everything_is_fine = false; + + // short-circuit if silent check + if ( $is_silent || ! current_user_can( 'activate_plugins' ) ) { + break; + } + + // otherwise, proceed to trigger an admin notice + $plugin_name = ! empty( $args['name'] ) ? $args['name'] : $slug; // use slug if no name + $plugin_link = ! empty( $args['link'] ) ? $args['link'] : false; + $is_installed = $this->is_plugin_installed( $slug ); + + if ( empty( $slug ) ) { + $error_msg = __( 'A CRM feature has an unknown missing dependency. Please contact support!' ); + ##WLREMOVE + $error_msg = __( 'A Jetpack CRM feature has an unknown missing dependency. Please contact support!' ); + ##/WLREMOVE + } elseif ( empty( $error_msg ) ) { + if ( ! $is_installed ) { + $error_msg = sprintf( __( '%1$s requires %2$s version %3$s or greater. Please install and activate %4$s to use this feature.', 'zero-bs-crm' ), $feature_name, $plugin_link ? '' . $plugin_name . '' : $plugin_name, $req_ver, $plugin_name ); + } elseif ( $is_installed && ! $is_good_ver ) { + $error_msg = sprintf( __( '%1$s requires %2$s version %3$s or greater, but version %4$s is currently installed. Please update %5$s to use this feature.', 'zero-bs-crm' ), $feature_name, $plugin_name, $req_ver, $cur_ver, $plugin_name ); + } elseif ( ! $is_active ) { + $error_msg = sprintf( __( '%1$s requires the %2$s plugin to be active. Please activate %3$s to use this feature.', 'zero-bs-crm' ), $feature_name, $plugin_name, $plugin_name ); + ##WLREMOVE + if ( ! empty( $args['kb_link'] ) ) { + $error_msg .= '

'; + $error_msg .= sprintf( __( 'To learn more about how this feature works, click here.', 'zero-bs-crm' ), $args['kb_link'] ); + } + ##/WLREMOVE + } + } + + $error_fn = function () use ( $error_msg ) { + $this->show_dependency_error( $error_msg ); + }; + add_action( 'admin_notices', $error_fn ); + } + return $everything_is_fine; + } /** * Show error message if feature's dependency requirements are not met * * @param string $error_msg Error message. */ - private function show_dependency_error( $error_msg ) { - if ( zeroBSCRM_isAdminPage() ) { - ?> -
-
-
-

-
-
- -

- +
+
+
+

+
+
+ +

+ all_plugins = get_plugins(); @@ -51,11 +51,11 @@ public function sniff_for_plugin( $args = array(), $is_silent = false ) { if ( // bad params empty( $args ) - || !isset( $args['feature_slug'] ) - || !isset( $args['plugin_slug'] ) - || !isset( $args['more_info_link'] ) + || ! isset( $args['feature_slug'] ) + || ! isset( $args['plugin_slug'] ) + || ! isset( $args['more_info_link'] ) // target plugin isn't active - || !is_plugin_active( $args['plugin_slug'] ) + || ! is_plugin_active( $args['plugin_slug'] ) // feature is already enabled || zeroBSCRM_isExtensionInstalled( $args['feature_slug'] ) ) { @@ -65,7 +65,7 @@ public function sniff_for_plugin( $args = array(), $is_silent = false ) { $is_dismissed = get_option( 'jpcrm_hide_' . $args['feature_slug'] . '_feature_alert', false ); // handle messaging if not silent - if ( !$is_silent && !$is_dismissed && current_user_can( 'activate_plugins' ) ) { + if ( ! $is_silent && ! $is_dismissed && current_user_can( 'activate_plugins' ) ) { $plugin_details = $this->all_plugins[ $args['plugin_slug'] ]; global $zbs; @@ -81,7 +81,7 @@ public function sniff_for_plugin( $args = array(), $is_silent = false ) { $this->alerts[] = array( 'feature_slug' => $args['feature_slug'], - 'message' => $message_template, + 'message' => $message_template, ); } @@ -94,7 +94,6 @@ public function sniff_for_plugin( $args = array(), $is_silent = false ) { * * Note that this will only show the first unused feature detected * that has not been dismissed - * */ public function show_feature_alerts() { // no untapped features, so no messaging needed @@ -106,17 +105,16 @@ public function show_feature_alerts() { $feature_alert_fn = function () { // only show first message; no need to overload user ?> -
-
-

alerts[0]['message'] ?>

-
-
+
+
+

alerts[0]['message']; ?>

+
+
*/ public function dismiss_alert( $feature_slug ) { - if ( !empty( $feature_slug ) ) { + if ( ! empty( $feature_slug ) ) { update_option( 'jpcrm_hide_' . $feature_slug . '_feature_alert', 1, false ); return true; diff --git a/projects/plugins/crm/includes/jpcrm-fonts.php b/projects/plugins/crm/includes/jpcrm-fonts.php index 4f2a816c26d0..efdaa4d45311 100644 --- a/projects/plugins/crm/includes/jpcrm-fonts.php +++ b/projects/plugins/crm/includes/jpcrm-fonts.php @@ -1,5 +1,5 @@ -libLoad('dompdf'); +global $zbs; +$zbs->libLoad( 'dompdf' ); use FontLib\Font; defined( 'ZEROBSCRM_PATH' ) || exit( 0 ); - - /* * Class encapsulating logic concerned with installing and using different fonts */ @@ -25,7 +24,7 @@ class JPCRM_Fonts { * @param: $cleaned_alphabetical bool - if true return the list with 'Noto' moved to back of string and re-ordered to be alphabetic * ... e.g. 'Noto Kufi Arabic' => 'Kufi Arabic (Noto)' */ - public function list_all_available( $cleaned_alphabetical=false ){ + public function list_all_available( $cleaned_alphabetical = false ) { // updated 17/04/24: Noto Sans, and added CJK fonts (JP, HK, TC, KR and SC) $font_json = @@ -33,10 +32,10 @@ public function list_all_available( $cleaned_alphabetical=false ){ $return_array = json_decode( $font_json, true ); - if ( $cleaned_alphabetical ){ + if ( $cleaned_alphabetical ) { $cleaned_array = array(); - foreach ( $return_array as $zip_name => $font_name ){ + foreach ( $return_array as $zip_name => $font_name ) { $cleaned_name = $font_name; if ( str_starts_with( $font_name, 'Noto Sans' ) ) { @@ -46,7 +45,7 @@ public function list_all_available( $cleaned_alphabetical=false ){ } // special cases here (lets us keep our font array clean but show more info in UI) - switch ( $cleaned_name ){ + switch ( $cleaned_name ) { case 'Boku2': $cleaned_name = 'Boku2 (JP)'; @@ -75,127 +74,114 @@ public function list_all_available( $cleaned_alphabetical=false ){ } return $return_array; - } /* * Converts a font-name to its zip filename */ - public function zip_to_font_name( $zip_file_name='' ){ - - return str_replace( '.zip', '', jpcrm_string_split_at_caps( $zip_file_name ) ); + public function zip_to_font_name( $zip_file_name = '' ) { + return str_replace( '.zip', '', jpcrm_string_split_at_caps( $zip_file_name ) ); } /* * Converts a font-name to its zip filename */ - public function font_name_to_zip( $font_name='' ){ - - return str_replace( ' ', '', $font_name ) . '.zip'; + public function font_name_to_zip( $font_name = '' ) { + return str_replace( ' ', '', $font_name ) . '.zip'; } /* * Converts a font-name to its *-Regular.ttf filename */ - public function font_name_to_regular_ttf_name( $font_name='' ){ - - return str_replace( ' ', '', $font_name ) . '-Regular.ttf'; + public function font_name_to_regular_ttf_name( $font_name = '' ) { + return str_replace( ' ', '', $font_name ) . '-Regular.ttf'; } /* * Converts a font-name to its ultimate directory */ - public function font_name_to_dir( $font_name='' ){ + public function font_name_to_dir( $font_name = '' ) { return str_replace( '.zip', '', $this->font_name_to_zip( $font_name ) ); - } /* * Converts a slug to a font name */ - public function font_slug_to_name( $font_slug='' ){ + public function font_slug_to_name( $font_slug = '' ) { return ucwords( str_replace( '-', ' ', $font_slug ) ); - } /* * Converts a font-name to a slug equivalent */ - public function font_name_to_slug( $font_name='' ){ + public function font_name_to_slug( $font_name = '' ) { global $zbs; return $zbs->DAL->makeSlug( $font_name ); - } /* * Checks a font is on our available list */ - public function font_is_available( $font_name='' ){ + public function font_is_available( $font_name = '' ) { $fonts = $this->list_all_available(); if ( isset( $fonts[ $this->font_name_to_zip( $font_name ) ] ) ) { - + return true; } return false; - } /* * Checks a font is on our available list */ - public function font_is_installed( $font_name='' ){ + public function font_is_installed( $font_name = '' ) { - if ( $this->font_is_available( $font_name ) ){ + if ( $this->font_is_available( $font_name ) ) { // Available? - if ( file_exists( ZEROBSCRM_INCLUDE_PATH . 'lib/dompdf-fonts/' . $this->font_name_to_dir( $font_name ) ) ){ + if ( file_exists( ZEROBSCRM_INCLUDE_PATH . 'lib/dompdf-fonts/' . $this->font_name_to_dir( $font_name ) ) ) { // Installed? (check setting) - $font_install_setting = zeroBSCRM_getSetting('pdf_extra_fonts_installed'); - if ( !is_array( $font_install_setting ) ){ + $font_install_setting = zeroBSCRM_getSetting( 'pdf_extra_fonts_installed' ); + if ( ! is_array( $font_install_setting ) ) { $font_install_setting = array(); } - if ( array_key_exists( $this->font_name_to_slug( $font_name ), $font_install_setting ) ){ + if ( array_key_exists( $this->font_name_to_slug( $font_name ), $font_install_setting ) ) { return true; } - - } - + } } return false; // font doesn't exist or isn't installed - } - /* * Installs fonts (which have already been downloaded, but are not marked installed) */ - public function install_font( $font_name='', $force_reinstall=false ) { + public function install_font( $font_name = '', $force_reinstall = false ) { // is available, and not installed (or $force_reinstall) - if ( - $this->font_is_available( $font_name ) && - ( !$this->font_is_installed( $font_name ) || $force_reinstall ) + if ( $this->font_is_available( $font_name ) && + ( ! $this->font_is_installed( $font_name ) || $force_reinstall ) ) { // get fonts dir - $fonts_dir = jpcrm_storage_fonts_dir_path(); + $fonts_dir = jpcrm_storage_fonts_dir_path(); $working_dir = zeroBSCRM_privatisedDirCheckWorks(); // Check if temp dir is valid - if ( empty( $working_dir['path'] ) || !$fonts_dir ) { + if ( empty( $working_dir['path'] ) || ! $fonts_dir ) { return false; } @@ -204,35 +190,35 @@ public function install_font( $font_name='', $force_reinstall=false ) { $font_directory_name = $this->font_name_to_dir( $font_name ); // Discern available variations - $font_regular_path = $working_dir . $this->font_name_to_regular_ttf_name( $font_name ); // 'NotoSans-Regular.ttf' - ALL variations have a `*-Regular.ttf` as at 01/12/21 - $font_bold_path = null; - $font_italic_path = null; + $font_regular_path = $working_dir . $this->font_name_to_regular_ttf_name( $font_name ); // 'NotoSans-Regular.ttf' - ALL variations have a `*-Regular.ttf` as at 01/12/21 + $font_bold_path = null; + $font_italic_path = null; $font_bolditalic_path = null; - if ( file_exists( $working_dir . $font_directory_name . '-Bold.ttf' ) ){ + if ( file_exists( $working_dir . $font_directory_name . '-Bold.ttf' ) ) { $font_bold_path = $working_dir . $font_directory_name . '-Bold.ttf'; } - if ( file_exists( $working_dir . $font_directory_name . '-Italic.ttf' ) ){ + if ( file_exists( $working_dir . $font_directory_name . '-Italic.ttf' ) ) { $font_italic_path = $working_dir . $font_directory_name . '-Italic.ttf'; } - if ( file_exists( $working_dir . $font_directory_name . '-BoldItalic.ttf' ) ){ + if ( file_exists( $working_dir . $font_directory_name . '-BoldItalic.ttf' ) ) { $font_bolditalic_path = $working_dir . $font_directory_name . '-BoldItalic.ttf'; } // Attempt to install - if ($this->load_font( - str_replace( ' ' ,'', $font_name ), // e.g. NotoSansJP - $font_regular_path, - $font_bold_path, - $font_italic_path, - $font_bolditalic_path - )){ + if ( $this->load_font( + str_replace( ' ', '', $font_name ), // e.g. NotoSansJP + $font_regular_path, + $font_bold_path, + $font_italic_path, + $font_bolditalic_path + ) ) { - global $zbs; + global $zbs; // Update setting - $font_install_setting = $zbs->settings->get('pdf_extra_fonts_installed'); - if ( !is_array( $font_install_setting ) ){ + $font_install_setting = $zbs->settings->get( 'pdf_extra_fonts_installed' ); + if ( ! is_array( $font_install_setting ) ) { $font_install_setting = array(); } $font_install_setting[ $this->font_name_to_slug( $font_name ) ] = time(); @@ -241,28 +227,25 @@ public function install_font( $font_name='', $force_reinstall=false ) { return true; } - } return false; - } - /* * Installs default fonts (which are extracted, but are not marked installed) * can use $this->extract_and_install_default_fonts() if from scratch (extracts + installs) */ - public function install_default_fonts( $force_reinstall = false ){ + public function install_default_fonts( $force_reinstall = false ) { global $zbsExtensionInstallError; // get fonts dir - $fonts_dir = jpcrm_storage_fonts_dir_path(); + $fonts_dir = jpcrm_storage_fonts_dir_path(); $working_dir = zeroBSCRM_privatisedDirCheckWorks(); // Check if temp dir is valid - if ( empty( $working_dir['path'] ) || !$fonts_dir ) { + if ( empty( $working_dir['path'] ) || ! $fonts_dir ) { $zbsExtensionInstallError = __( 'Jetpack CRM was not able to create the directories it needs in order to install fonts for the PDF Engine.', 'zero-bs-crm' ); return false; } @@ -270,11 +253,11 @@ public function install_default_fonts( $force_reinstall = false ){ $working_dir = $working_dir['path'] . '/'; // also install the font(s) if not already installed (if present) - $fontsInstalled = zeroBSCRM_getSetting('pdf_fonts_installed'); + $fontsInstalled = zeroBSCRM_getSetting( 'pdf_fonts_installed' ); if ( ( $fontsInstalled !== 1 && file_exists( $fonts_dir . 'fonts-info.txt' ) ) || - ( !$this->default_fonts_installed() ) + ( ! $this->default_fonts_installed() ) || $force_reinstall ) { @@ -297,14 +280,11 @@ public function install_default_fonts( $force_reinstall = false ){ $zbsExtensionInstallError = __( 'Jetpack CRM was not able to install fonts for the PDF engine.', 'zero-bs-crm' ); return false; } - } return true; - } - /** * Installs a new font family * This function maps a font-family name to a font. It tries to locate the @@ -323,100 +303,107 @@ public function install_default_fonts( $force_reinstall = false ){ * * @throws Exception */ - public function install_font_family($dompdf, $fontname, $normal, $bold = null, $italic = null, $bold_italic = null, $debug = false) { + public function install_font_family( $dompdf, $fontname, $normal, $bold = null, $italic = null, $bold_italic = null, $debug = false ) { - try { + try { $fontMetrics = $dompdf->getFontMetrics(); // Check if the base filename is readable - if ( !is_readable($normal) ) { - throw new Exception("Unable to read '$normal'."); + if ( ! is_readable( $normal ) ) { + throw new Exception( "Unable to read '$normal'." ); } - $dir = dirname($normal); - $basename = basename($normal); - $last_dot = strrpos($basename, '.'); - if ($last_dot !== false) { - $file = substr($basename, 0, $last_dot); - $ext = strtolower(substr($basename, $last_dot)); + $dir = dirname( $normal ); + $basename = basename( $normal ); + $last_dot = strrpos( $basename, '.' ); + if ( $last_dot !== false ) { + $file = substr( $basename, 0, $last_dot ); + $ext = strtolower( substr( $basename, $last_dot ) ); } else { $file = $basename; - $ext = ''; + $ext = ''; } // dompdf will eventually support .otf, but for now limit to .ttf - if ( !in_array($ext, array(".ttf")) ) { - throw new Exception("Unable to process fonts of type '$ext'."); + if ( ! in_array( $ext, array( '.ttf' ) ) ) { + throw new Exception( "Unable to process fonts of type '$ext'." ); } // Try $file_Bold.$ext etc. $path = "$dir/$file"; $patterns = array( - "bold" => array("_Bold", "b", "B", "bd", "BD"), - "italic" => array("_Italic", "i", "I"), - "bold_italic" => array("_Bold_Italic", "bi", "BI", "ib", "IB"), + 'bold' => array( '_Bold', 'b', 'B', 'bd', 'BD' ), + 'italic' => array( '_Italic', 'i', 'I' ), + 'bold_italic' => array( '_Bold_Italic', 'bi', 'BI', 'ib', 'IB' ), ); - foreach ($patterns as $type => $_patterns) { - if ( !isset($$type) || !is_readable($$type) ) { - foreach($_patterns as $_pattern) { - if ( is_readable("$path$_pattern$ext") ) { + foreach ( $patterns as $type => $_patterns ) { + if ( ! isset( $$type ) || ! is_readable( $$type ) ) { + foreach ( $_patterns as $_pattern ) { + if ( is_readable( "$path$_pattern$ext" ) ) { $$type = "$path$_pattern$ext"; break; } } - if ( is_null($$type) ) - if ($debug) echo ("Unable to find $type face file.\n"); + if ( $$type === null ) { + if ( $debug ) { + echo ( "Unable to find $type face file.\n" ); + } + } } } - $fonts = compact("normal", "bold", "italic", "bold_italic"); + $fonts = compact( 'normal', 'bold', 'italic', 'bold_italic' ); $entry = array(); // Copy the files to the font directory. - foreach ($fonts as $var => $src) { - if ( is_null($src) ) { - $entry[$var] = $dompdf->getOptions()->get('fontDir') . '/' . mb_substr(basename($normal), 0, -4); + foreach ( $fonts as $var => $src ) { + if ( $src === null ) { + $entry[ $var ] = $dompdf->getOptions()->get( 'fontDir' ) . '/' . mb_substr( basename( $normal ), 0, -4 ); continue; } // Verify that the fonts exist and are readable - if ( !is_readable($src) ) { - throw new Exception("Requested font '$src' is not readable"); + if ( ! is_readable( $src ) ) { + throw new Exception( "Requested font '$src' is not readable" ); } - $dest = $dompdf->getOptions()->get('fontDir') . '/' . basename($src); + $dest = $dompdf->getOptions()->get( 'fontDir' ) . '/' . basename( $src ); - // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable, Generic.WhiteSpace.ScopeIndent.IncorrectExact -- TODO: Fix these. + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- TODO: Fix these. if ( ! is_writable( dirname( $dest ) ) ) { - throw new Exception("Unable to write to destination '$dest'."); + throw new Exception( "Unable to write to destination '$dest'." ); + } + + if ( $debug ) { + echo "Copying $src to $dest...\n"; } - if ($debug) echo "Copying $src to $dest...\n"; + if ( ! copy( $src, $dest ) ) { + throw new Exception( "Unable to copy '$src' to '$dest'" ); + } + + $entry_name = mb_substr( $dest, 0, -4 ); - if ( !copy($src, $dest) ) { - throw new Exception("Unable to copy '$src' to '$dest'"); + if ( $debug ) { + echo "Generating Adobe Font Metrics for $entry_name...\n"; } - $entry_name = mb_substr($dest, 0, -4); - - if ($debug) echo "Generating Adobe Font Metrics for $entry_name...\n"; - - $font_obj = Font::load($dest); - $font_obj->saveAdobeFontMetrics("$entry_name.ufm"); + $font_obj = Font::load( $dest ); + $font_obj->saveAdobeFontMetrics( "$entry_name.ufm" ); $font_obj->close(); - $entry[$var] = $entry_name; + $entry[ $var ] = $entry_name; unlink( $src ); } // Store the fonts in the lookup table - $fontMetrics->setFontFamily($fontname, $entry); + $fontMetrics->setFontFamily( $fontname, $entry ); // Save the changes $fontMetrics->saveFontFamilies(); @@ -424,58 +411,57 @@ public function install_font_family($dompdf, $fontname, $normal, $bold = null, $ // Fini return true; - } catch (Exception $e){ + } catch ( Exception $e ) { // nada } return false; - } /* * Retrieves a font zip from our CDN and installs it locally */ - public function retrieve_and_install_specific_font( $font_name='', $force_reinstall = false){ + public function retrieve_and_install_specific_font( $font_name = '', $force_reinstall = false ) { global $zbsExtensionInstallError; // font exists? - if ( !$this->font_is_available( $font_name) ){ + if ( ! $this->font_is_available( $font_name ) ) { return false; } // font already installed? - if ( $this->font_is_installed( $font_name ) && !$force_reinstall ){ + if ( $this->font_is_installed( $font_name ) && ! $force_reinstall ) { return true; } // get fonts dir - $fonts_dir = jpcrm_storage_fonts_dir_path(); + $fonts_dir = jpcrm_storage_fonts_dir_path(); $working_dir = zeroBSCRM_privatisedDirCheckWorks(); // Check if temp dir is valid - if ( empty( $working_dir['path'] ) || !$fonts_dir ) { + if ( empty( $working_dir['path'] ) || ! $fonts_dir ) { $zbsExtensionInstallError = __( 'Jetpack CRM was not able to create the directories it needs in order to install fonts for the PDF Engine.', 'zero-bs-crm' ); return false; } - $working_dir = $working_dir['path'] . '/'; + $working_dir = $working_dir['path'] . '/'; $font_file_name = $this->font_name_to_regular_ttf_name( $font_name ); // Already downloaded, so proceed to install - if ( file_exists( $working_dir . $font_file_name) ) { + if ( file_exists( $working_dir . $font_file_name ) ) { return $this->install_font( $font_name ); } // Retrieve & install the font $remote_zip_name = $this->font_name_to_zip( $font_name ); - $temp_path = tempnam( sys_get_temp_dir(), 'crmfont' ); + $temp_path = tempnam( sys_get_temp_dir(), 'crmfont' ); // Several large font files may timeout when downloading. Increase the timeout for these files. $large_font_files = array( ' Noto Sans Simplified Chinese', ' Noto Serif Display', ' Noto Sans', ' Noto Sans Display', ' Noto Sans Taiwan', ' Noto Sans Hong Kong', ' Noto Sans Japanese', ' Noto Sans Korean', ' Noto Sans Mono' ); @@ -490,9 +476,9 @@ function () { // Retrieve zip global $zbs; - if ( !zeroBSCRM_retrieveFile( $zbs->urls['extdlfonts'] . $remote_zip_name, $temp_path ) ) { + if ( ! zeroBSCRM_retrieveFile( $zbs->urls['extdlfonts'] . $remote_zip_name, $temp_path ) ) { // Something failed - $zbsExtensionInstallError = __('Jetpack CRM was not able to download the fonts it needs for the PDF Engine.',"zero-bs-crm").' '.__('(fonts)','zero-bs-crm'); + $zbsExtensionInstallError = __( 'Jetpack CRM was not able to download the fonts it needs for the PDF Engine.', 'zero-bs-crm' ) . ' ' . __( '(fonts)', 'zero-bs-crm' ); unlink( $temp_path ); return false; } @@ -502,12 +488,12 @@ function () { unlink( $temp_path ); // appears to have worked - if ( !$expanded || !file_exists( $working_dir . $font_file_name ) ) { + if ( ! $expanded || ! file_exists( $working_dir . $font_file_name ) ) { // Add error msg - $zbsExtensionInstallError = __('CRM was not able to retrieve the requested font.',"zero-bs-crm") . ' ' . __('(Failed to install font.)',"zero-bs-crm"); + $zbsExtensionInstallError = __( 'CRM was not able to retrieve the requested font.', 'zero-bs-crm' ) . ' ' . __( '(Failed to install font.)', 'zero-bs-crm' ); ##WLREMOVE - $zbsExtensionInstallError = __('Jetpack CRM was not able to retrieve the requested font.',"zero-bs-crm") . ' ' . __('(Failed to install font.)',"zero-bs-crm"); + $zbsExtensionInstallError = __( 'Jetpack CRM was not able to retrieve the requested font.', 'zero-bs-crm' ) . ' ' . __( '(Failed to install font.)', 'zero-bs-crm' ); ##/WLREMOVE return false; @@ -516,25 +502,23 @@ function () { // install the font return $this->install_font( $font_name, true ); - } - /* * Extract (and install) default fonts which dompdf uses to provide global lang supp * This function is used if somebody were to delete these default fonts from jpcrm-storage. * Instead, use retrieve_and_install() to retrieve locale specific fonts (from v4.7.0) */ - public function extract_and_install_default_fonts(){ + public function extract_and_install_default_fonts() { global $zbsExtensionInstallError; // get fonts dir - $fonts_dir = jpcrm_storage_fonts_dir_path(); + $fonts_dir = jpcrm_storage_fonts_dir_path(); $working_dir = zeroBSCRM_privatisedDirCheckWorks(); // Check if temp dir is valid - if ( empty( $working_dir['path'] ) || !$fonts_dir ) { + if ( empty( $working_dir['path'] ) || ! $fonts_dir ) { $zbsExtensionInstallError = __( 'Jetpack CRM was not able to create the directories it needs in order to install fonts for the PDF Engine.', 'zero-bs-crm' ); return false; } @@ -551,10 +535,10 @@ public function extract_and_install_default_fonts(){ $expanded = zeroBSCRM_expandArchive( ZEROBSCRM_PATH . 'data/pdffonts.zip', $working_dir ); // Check success? - if ( !$expanded || !file_exists( $working_dir . 'fonts-info.txt' ) ) { + if ( ! $expanded || ! file_exists( $working_dir . 'fonts-info.txt' ) ) { // Add error msg - $zbsExtensionInstallError = __('Jetpack CRM was not able to extract the fonts it needs for the PDF Engine.',"zero-bs-crm").' '.__('(fonts)','zero-bs-crm'); + $zbsExtensionInstallError = __( 'Jetpack CRM was not able to extract the fonts it needs for the PDF Engine.', 'zero-bs-crm' ) . ' ' . __( '(fonts)', 'zero-bs-crm' ); // Return fail return false; @@ -564,8 +548,6 @@ public function extract_and_install_default_fonts(){ // install 'em return $this->install_default_fonts( true ); - - } /** @@ -606,7 +588,7 @@ public function load_font( $font_name = '', $regular_file = '', $bold_file = nul /* * Retrieves the font cache from dompdf and returns all loaded fonts */ - public function loaded_fonts(){ + public function loaded_fonts() { $dompdf_font_cache_file = jpcrm_storage_fonts_dir_path() . 'installed-fonts.json'; @@ -619,17 +601,16 @@ public function loaded_fonts(){ } return array(); - } /* * Returns bool whether or not our key font (Noto Sans global) is installed according to dompdf */ - public function default_fonts_installed(){ + public function default_fonts_installed() { $existing_fonts = $this->loaded_fonts(); - if ( isset( $existing_fonts->notosansglobal ) ){ + if ( isset( $existing_fonts->notosansglobal ) ) { return true; } diff --git a/projects/plugins/crm/includes/jpcrm-mail-templating.php b/projects/plugins/crm/includes/jpcrm-mail-templating.php index ed5d2985e20a..f76f2371b633 100644 --- a/projects/plugins/crm/includes/jpcrm-mail-templating.php +++ b/projects/plugins/crm/includes/jpcrm-mail-templating.php @@ -1,5 +1,5 @@ - - //inside a

if not defined carefully, better to just do wp_kses_post() - //https://codex.wordpress.org/Function_Reference/wp_kses_post also sanitizes. - $content = wp_kses_post($content); + // acceptable html here is a bit flawed as it needs to be specifically done otherwise it will strip a + // inside a

if not defined carefully, better to just do wp_kses_post() + // https://codex.wordpress.org/Function_Reference/wp_kses_post also sanitizes. + $content = wp_kses_post( $content ); return $content; } -function zeroBSCRM_mailTemplate_emailPreview($templateID=-1){ +function zeroBSCRM_mailTemplate_emailPreview( $templateID = -1 ) { global $zbs; - $html = ''; $bodyHTML = ''; + $html = ''; + $bodyHTML = ''; - if ( $templateID > 0 ){ + if ( $templateID > 0 ) { // retrieve template - $html = jpcrm_retrieve_template( 'emails/default-email.html', false ); - $message_content = zeroBSCRM_mailTemplate_get($templateID); - if (isset($message_content->zbsmail_body)) $bodyHTML = $message_content->zbsmail_body; + $html = jpcrm_retrieve_template( 'emails/default-email.html', false ); + $message_content = zeroBSCRM_mailTemplate_get( $templateID ); + if ( isset( $message_content->zbsmail_body ) ) { + $bodyHTML = $message_content->zbsmail_body; + } // load templater - $placeholder_templating = $zbs->get_templating(); + $placeholder_templating = $zbs->get_templating(); // build replacements array // ... start with generic replaces (e.g. loginlink, loginbutton) - $replacements = $placeholder_templating->get_generic_replacements(); + $replacements = $placeholder_templating->get_generic_replacements(); + if ( isset( $message_content->zbsmail_body ) ) { + $bodyHTML = $message_content->zbsmail_body; + } - if (isset($message_content->zbsmail_body)) $bodyHTML = $message_content->zbsmail_body; - // preview sublne - $subLine = __("This is a Jetpack CRM email template preview
This footer text is not shown in live emails.",'zero-bs-crm'); - $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $html ); + $subLine = __( 'This is a Jetpack CRM email template preview
This footer text is not shown in live emails.', 'zero-bs-crm' ); + $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $html ); - $replacements['unsub-line'] = $subLine; - $replacements['powered-by'] = zeroBSCRM_mailTemplate_poweredByHTML(); + $replacements['unsub-line'] = $subLine; + $replacements['powered-by'] = zeroBSCRM_mailTemplate_poweredByHTML(); $replacements['email-from-name'] = zeroBSCRM_mailDelivery_defaultFromname(); - //process the template specific ##PLACEHOLDER## to actual viewable stuff... - if ( $templateID == 1 ){ - + // process the template specific ##PLACEHOLDER## to actual viewable stuff... + if ( $templateID == 1 ) { + // client portal // Replace some common ones with generic examples too: - $replacements['email'] = 'your.user@email.com'; - $replacements['login-url'] = site_url('clients/login'); + $replacements['email'] = 'your.user@email.com'; + $replacements['login-url'] = site_url( 'clients/login' ); // replace vars $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact' ), $html, $replacements ); } - if ( $templateID == 2 ){ + if ( $templateID == 2 ) { // quote accepted - $replacements['quote-title'] = __('Example Quotation #101','zero-bs-crm'); - $replacements['quote-url'] = site_url('clients/login'); + $replacements['quote-title'] = __( 'Example Quotation #101', 'zero-bs-crm' ); + $replacements['quote-url'] = site_url( 'clients/login' ); $replacements['quote-edit-url'] = admin_url(); - // replace vars - $html = $placeholder_templating->replace_placeholders( array( 'global', 'quote', 'contact' ), $html, $replacements ); - + // replace vars + $html = $placeholder_templating->replace_placeholders( array( 'global', 'quote', 'contact' ), $html, $replacements ); } - if ( $templateID == 3 ){ + if ( $templateID == 3 ) { - //invoice template + // invoice template - $i=0; + $i = 0; $logo_url = ''; ##WLREMOVE $logo_url = $zbs->urls['crm-logo']; ##/WLREMOVE - $lineitems = array( array( 'title' => __( 'Your Invoice Item', 'zero-bs-crm' ), @@ -138,17 +137,17 @@ function zeroBSCRM_mailTemplate_emailPreview($templateID=-1){ $replacements['biz-info'] = $biz_info_table; $viewInPortal = ''; - $invoiceID = ''; + $invoiceID = ''; // got portal? - //if (isset($invsettings['feat_portal']) && !empty($invsettings['feat_portal'])){ - if (zeroBSCRM_isExtensionInstalled('portal')){ + // if (isset($invsettings['feat_portal']) && !empty($invsettings['feat_portal'])){ + if ( zeroBSCRM_isExtensionInstalled( 'portal' ) ) { // view on portal (hashed?) - $viewInPortalURL = zeroBSCRM_portal_linkObj($invoiceID,ZBS_TYPE_INVOICE); //zeroBS_portal_link('invoices',$invoiceID); + $viewInPortalURL = zeroBSCRM_portal_linkObj( $invoiceID, ZBS_TYPE_INVOICE ); // zeroBS_portal_link('invoices',$invoiceID); // if viewing in portal? - $viewInPortal = '

'.zeroBSCRM_mailTemplate_emailSafeButton($viewInPortalURL,__('View Invoice','zero-bs-crm')).'
'; + $viewInPortal = '
' . zeroBSCRM_mailTemplate_emailSafeButton( $viewInPortalURL, __( 'View Invoice', 'zero-bs-crm' ) ) . '
'; } @@ -158,27 +157,26 @@ function zeroBSCRM_mailTemplate_emailPreview($templateID=-1){ // replace vars $html = $placeholder_templating->replace_placeholders( array( 'global', 'invoice', 'contact', 'company' ), $html, $replacements ); - } // new proposal - if ( $templateID == 4 ){ + if ( $templateID == 4 ) { - $replacements['quote-title'] = __('Example Quotation #101','zero-bs-crm'); - $replacements['quote-url'] = site_url('clients/login'); + $replacements['quote-title'] = __( 'Example Quotation #101', 'zero-bs-crm' ); + $replacements['quote-url'] = site_url( 'clients/login' ); $viewInPortal = ''; - $quoteID = ''; + $quoteID = ''; // got portal? - //if (isset($invsettings['feat_portal']) && !empty($invsettings['feat_portal'])){ - if (zeroBSCRM_isExtensionInstalled('portal')){ + // if (isset($invsettings['feat_portal']) && !empty($invsettings['feat_portal'])){ + if ( zeroBSCRM_isExtensionInstalled( 'portal' ) ) { // view on portal (hashed?) - $viewInPortalURL = zeroBSCRM_portal_linkObj($quoteID,ZBS_TYPE_QUOTE); + $viewInPortalURL = zeroBSCRM_portal_linkObj( $quoteID, ZBS_TYPE_QUOTE ); // if viewing in portal? - $viewInPortal = '
'.zeroBSCRM_mailTemplate_emailSafeButton($viewInPortalURL,__('View Proposal','zero-bs-crm')).'
'; + $viewInPortal = '
' . zeroBSCRM_mailTemplate_emailSafeButton( $viewInPortalURL, __( 'View Proposal', 'zero-bs-crm' ) ) . '
'; } @@ -189,9 +187,8 @@ function zeroBSCRM_mailTemplate_emailPreview($templateID=-1){ $html = $placeholder_templating->replace_placeholders( array( 'global', 'quote', 'contact' ), $html, $replacements ); } - // task - if ( $templateID == 5 ){ + if ( $templateID == 5 ) { $replacements['task-title'] = __( 'Example Task #101', 'zero-bs-crm' ); $replacements['task-link'] = '
' . zeroBSCRM_mailTemplate_emailSafeButton( admin_url(), __( 'View Task', 'zero-bs-crm' ) ) . '
'; @@ -199,161 +196,159 @@ function zeroBSCRM_mailTemplate_emailPreview($templateID=-1){ $replacements['contact-lname'] = __( 'Last-Name', 'zero-bs-crm' ); $replacements['contact-fullname'] = __( 'Full-Name', 'zero-bs-crm' ); - // replace vars - $html = $placeholder_templating->replace_placeholders( array( 'global', 'event' ), $html, $replacements ); + // replace vars + $html = $placeholder_templating->replace_placeholders( array( 'global', 'event' ), $html, $replacements ); } - // Your Client Portal Password - if ( $templateID == 6 ){ + if ( $templateID == 6 ) { $replacements['password'] = '********'; - $replacements['email'] = 'your.user@email.com'; + $replacements['email'] = 'your.user@email.com'; - // replace vars - $html = $placeholder_templating->replace_placeholders( array( 'global' ), $html, $replacements ); + // replace vars + $html = $placeholder_templating->replace_placeholders( array( 'global' ), $html, $replacements ); } // Your Statement - if ( $templateID == 7 ){ + if ( $templateID == 7 ) { - // replace vars - $html = $placeholder_templating->replace_placeholders( array( 'global' ), $html, $replacements ); + // replace vars + $html = $placeholder_templating->replace_placeholders( array( 'global' ), $html, $replacements ); } - - - } - + } return $html; - } - // Check if attempting to preview email template -function zeroBSCRM_preview_email_template(){ +function zeroBSCRM_preview_email_template() { global $zbs; // if trying to preview - if (isset($_GET['zbsmail-template-preview']) && $_GET['zbsmail-template-preview'] == 1){ - - // if rights - if ( current_user_can( 'admin_zerobs_manage_options' ) ) { + if ( isset( $_GET['zbsmail-template-preview'] ) && $_GET['zbsmail-template-preview'] == 1 ) { + + // if rights + if ( current_user_can( 'admin_zerobs_manage_options' ) ) { $html = ''; - if (isset( $_GET['template_id'] ) && !empty( $_GET['template_id'] ) ){ + if ( isset( $_GET['template_id'] ) && ! empty( $_GET['template_id'] ) ) { - $templateID = (int)sanitize_text_field( $_GET['template_id'] ); - echo zeroBSCRM_mailTemplate_emailPreview($templateID); + $templateID = (int) sanitize_text_field( $_GET['template_id'] ); + echo zeroBSCRM_mailTemplate_emailPreview( $templateID ); } else { // load templater - $placeholder_templating = $zbs->get_templating(); + $placeholder_templating = $zbs->get_templating(); // retrieve template $html = jpcrm_retrieve_template( 'emails/default-email.html', false ); $message_content = ''; - $unsub_line = ''; + $unsub_line = ''; ##WLREMOVE## $message_content = "

Welcome to Jetpack CRM Email Templates

"; - $unsub_line = __("Thanks for using Jetpack CRM",'zero-bs-crm'); + $unsub_line = __( 'Thanks for using Jetpack CRM', 'zero-bs-crm' ); ##/WLREMOVE## - $message_content .= "
" . __("This is example content for the email template preview.

This content will be replaced by what you have in your system email templates

", 'zero-bs-crm') . "
"; + $message_content .= "
" . __( 'This is example content for the email template preview.

This content will be replaced by what you have in your system email templates

', 'zero-bs-crm' ) . '
'; // replacements - echo $placeholder_templating->replace_placeholders( array( 'global', 'invoice' ), $html, array( + echo $placeholder_templating->replace_placeholders( + array( 'global', 'invoice' ), + $html, + array( - 'title' => esc_html__('Template Preview','zero-bs-crm'), - 'msg-content' => $message_content, - 'unsub-line' => esc_html( $unsub_line ), - 'powered-by' => zeroBSCRM_mailTemplate_poweredByHTML(), - 'email-from-name' => esc_html( zeroBSCRM_mailDelivery_defaultFromname() ) + 'title' => esc_html__( 'Template Preview', 'zero-bs-crm' ), + 'msg-content' => $message_content, + 'unsub-line' => esc_html( $unsub_line ), + 'powered-by' => zeroBSCRM_mailTemplate_poweredByHTML(), + 'email-from-name' => esc_html( zeroBSCRM_mailDelivery_defaultFromname() ), - )); + ) + ); - } + } die( 0 ); } } -} add_action('init','zeroBSCRM_preview_email_template'); - +} add_action( 'init', 'zeroBSCRM_preview_email_template' ); - -/* =========================================================== - ZBS Templating - Load Default Templates / Restore Default - ========================================================== - Noting here that although zeroBSCRM_mail_retrieveWrapTemplate has been deprecated (4.5.0), +/* +=========================================================== + ZBS Templating - Load Default Templates / Restore Default + ========================================================== + Noting here that although zeroBSCRM_mail_retrieveWrapTemplate has been deprecated (4.5.0), This one is not, the thinking being these are used to load specific email bodies which (as of now) are loaded into the DB via zeroBSCRM_populateEmailTemplateList() and then edited via UI ...so there is probably no need to move these out of UI into templated files. */ -function zeroBSCRM_mail_retrieveDefaultBodyTemplate($template='maintemplate'){ +function zeroBSCRM_mail_retrieveDefaultBodyTemplate( $template = 'maintemplate' ) { - $templatedHTML = ''; + $templatedHTML = ''; - if (function_exists('file_get_contents')){ + if ( function_exists( 'file_get_contents' ) ) { #} templates $acceptableTemplates = array( 'maintemplate', 'clientportal', 'invoicesent', 'quoteaccepted', 'quotesent', 'tasknotification', 'clientportalpwreset', 'invoicestatementsent' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase - if (in_array($template, $acceptableTemplates)){ + if ( in_array( $template, $acceptableTemplates ) ) { // 2.98.6+ translated. maintemplate was a misnomer - if ($template == 'maintemplate') $template = 'email-body'; - - try { - - #} Build from default template - see the useful - http://www.leemunroe.com/responsive-html-email-template/ - $templatedHTML = file_get_contents(ZEROBSCRM_PATH.'html/templates/'.$template.'.html'); + if ( $template == 'maintemplate' ) { + $template = 'email-body'; + } + try { - } catch (Exception $e){ + #} Build from default template - see the useful - http://www.leemunroe.com/responsive-html-email-template/ + $templatedHTML = file_get_contents( ZEROBSCRM_PATH . 'html/templates/' . $template . '.html' ); - #} Nada + } catch ( Exception $e ) { - } + #} Nada + } } - } return $templatedHTML; } -/* ====================================================== +/* +====================================================== / ZBS Templating - Load Initial HTML - ====================================================== */ + ====================================================== */ -/* ====================================================== +/* +====================================================== ZBS Quotes - Generate HTML (notification emails) - ====================================================== */ + ====================================================== */ function zeroBSCRM_quote_generateNotificationHTML( $quoteID = -1, $return = true ) { global $zbs; - if ( !empty( $quoteID ) ) { + if ( ! empty( $quoteID ) ) { $quote_contact_id = $zbs->DAL->quotes->getQuoteContactID( $quoteID ); - $quote_contact = $zbs->DAL->contacts->getContact( $quote_contact_id ); - $html = ''; - $pWrap = '

'; + $quote_contact = $zbs->DAL->contacts->getContact( $quote_contact_id ); + $html = ''; + $pWrap = '

'; // retrieve template $templatedHTML = jpcrm_retrieve_template( 'emails/default-email.html', false ); // Act - if ( !empty( $templatedHTML ) ) { + if ( ! empty( $templatedHTML ) ) { // Actual body: $bodyHTML = ''; @@ -370,31 +365,31 @@ function zeroBSCRM_quote_generateNotificationHTML( $quoteID = -1, $return = true if ( isset( $quote ) && is_array( $quote ) ) { $proposalTitle = ''; - if ( !empty( $quote['title'] ) ) { + if ( ! empty( $quote['title'] ) ) { $proposalTitle = $quote['title']; } // vars - $zbs_biz_name = zeroBSCRM_getSetting( 'businessname' ); - $zbs_biz_yourname = zeroBSCRM_getSetting( 'businessyourname' ); - $zbs_biz_extra = zeroBSCRM_getSetting( 'businessextra' ); - $zbs_biz_youremail = zeroBSCRM_getSetting( 'businessyouremail' ); - $zbs_biz_yoururl = zeroBSCRM_getSetting( 'businessyoururl' ); - $zbs_settings_slug = admin_url( 'admin.php?page=' . $zbs->slugs['settings'] ) . '&tab=quotes'; - $quote_url = zeroBSCRM_portal_linkObj( $quoteID, ZBS_TYPE_QUOTE ); + $zbs_biz_name = zeroBSCRM_getSetting( 'businessname' ); + $zbs_biz_yourname = zeroBSCRM_getSetting( 'businessyourname' ); + $zbs_biz_extra = zeroBSCRM_getSetting( 'businessextra' ); + $zbs_biz_youremail = zeroBSCRM_getSetting( 'businessyouremail' ); + $zbs_biz_yoururl = zeroBSCRM_getSetting( 'businessyoururl' ); + $zbs_settings_slug = admin_url( 'admin.php?page=' . $zbs->slugs['settings'] ) . '&tab=quotes'; + $quote_url = zeroBSCRM_portal_linkObj( $quoteID, ZBS_TYPE_QUOTE ); $proposalEmailTitle = __( 'Proposal Notification', 'zero-bs-crm' ); // build content $message_content = zeroBSCRM_mailTemplate_get( ZBSEMAIL_NEWQUOTE ); - $bodyHTML = $message_content->zbsmail_body; + $bodyHTML = $message_content->zbsmail_body; // replacements $bodyHTML - $replacements['quote-url'] = $quote_url; + $replacements['quote-url'] = $quote_url; $replacements['quote-title'] = $proposalTitle; $replacements['quote-value'] = $quote['value'] ? zeroBSCRM_formatCurrency( $quote['value'] ) : ''; $viewInPortal = ''; - $quoteID = ''; + $quoteID = ''; // got portal? if ( zeroBSCRM_isExtensionInstalled( 'portal' ) ) { // view on portal (hashed?) @@ -406,11 +401,19 @@ function zeroBSCRM_quote_generateNotificationHTML( $quoteID = -1, $return = true $replacements['portal-view-button'] = $viewInPortal; // build msg-content html - $bodyHTML = $placeholder_templating->replace_placeholders( array( 'global', 'quote', 'contact' ), $bodyHTML, $replacements, array( ZBS_TYPE_QUOTE => $quote, ZBS_TYPE_CONTACT => $quote_contact ) ); + $bodyHTML = $placeholder_templating->replace_placeholders( + array( 'global', 'quote', 'contact' ), + $bodyHTML, + $replacements, + array( + ZBS_TYPE_QUOTE => $quote, + ZBS_TYPE_CONTACT => $quote_contact, + ) + ); // For now, use this, ripped from invoices: // (We need to centralise) - $bizInfoTable = ''; + $bizInfoTable = '
'; $bizInfoTable .= ''; $bizInfoTable .= ''; $bizInfoTable .= ''; @@ -420,17 +423,17 @@ function zeroBSCRM_quote_generateNotificationHTML( $quoteID = -1, $return = true // phony - needs unsub $unsub_line = __( 'You have received this notification because a proposal has been sent to you', 'zero-bs-crm' ); - if ( isset( $zbs_biz_name ) && !empty( $zbs_biz_name ) ) { + if ( isset( $zbs_biz_name ) && ! empty( $zbs_biz_name ) ) { $unsub_line .= ' by ' . $zbs_biz_name; } $unsub_line .= '. ' . __( 'If you believe this was sent in error, please reply and let us know.', 'zero-bs-crm' ); // build body html - $replacements = $placeholder_templating->get_generic_replacements(); - $replacements['title'] = $proposalEmailTitle; + $replacements = $placeholder_templating->get_generic_replacements(); + $replacements['title'] = $proposalEmailTitle; $replacements['msg-content'] = $bodyHTML; - $replacements['unsub-line'] = $unsub_line; - $replacements['biz-info'] = $bizInfoTable; + $replacements['unsub-line'] = $unsub_line; + $replacements['biz-info'] = $bizInfoTable; $settings = $zbs->settings->getAll(); if ( $settings['currency'] && $settings['currency']['strval'] ) { @@ -441,13 +444,12 @@ function zeroBSCRM_quote_generateNotificationHTML( $quoteID = -1, $return = true } // return - if ( !$return ) { + if ( ! $return ) { echo $html; exit( 0 ); } - } return $html; @@ -457,17 +459,16 @@ function zeroBSCRM_quote_generateNotificationHTML( $quoteID = -1, $return = true return; } - #} sent to quote creator function zeroBSCRM_quote_generateAcceptNotifHTML( $quoteID = -1, $quoteSignedBy = '', $return = true ) { global $zbs; - if ( !empty( $quoteID ) ) { + if ( ! empty( $quoteID ) ) { $quote_contact_id = $zbs->DAL->quotes->getQuoteContactID( $quoteID ); - $quote_contact = $zbs->DAL->contacts->getContact( $quote_contact_id ); + $quote_contact = $zbs->DAL->contacts->getContact( $quote_contact_id ); - $html = ''; + $html = ''; $pWrap = '

'; // retrieve template @@ -480,7 +481,7 @@ function zeroBSCRM_quote_generateAcceptNotifHTML( $quoteID = -1, $quoteSignedBy $replacements = $placeholder_templating->get_generic_replacements(); // Act - if ( !empty( $templatedHTML ) ) { + if ( ! empty( $templatedHTML ) ) { // Actual body: $bodyHTML = ''; @@ -491,25 +492,33 @@ function zeroBSCRM_quote_generateAcceptNotifHTML( $quoteID = -1, $quoteSignedBy if ( isset( $quote ) && is_array( $quote ) ) { $proposalTitle = ''; - if ( !empty( $quote['title'] ) ) { + if ( ! empty( $quote['title'] ) ) { $proposalTitle = $quote['title']; } - $message_content = zeroBSCRM_mailTemplate_get( ZBSEMAIL_QUOTEACCEPTED ); - $bodyHTML = $message_content->zbsmail_body; + $message_content = zeroBSCRM_mailTemplate_get( ZBSEMAIL_QUOTEACCEPTED ); + $bodyHTML = $message_content->zbsmail_body; $proposalEmailTitle = __( 'Proposal Notification', 'zero-bs-crm' ); - $zbs_biz_name = zeroBSCRM_getSetting( 'businessname' ); - $zbs_biz_yourname = zeroBSCRM_getSetting( 'businessyourname' ); - $zbs_biz_extra = zeroBSCRM_getSetting( 'businessextra' ); - $zbs_biz_youremail = zeroBSCRM_getSetting( 'businessyouremail' ); - $zbs_biz_yoururl = zeroBSCRM_getSetting( 'businessyoururl' ); + $zbs_biz_name = zeroBSCRM_getSetting( 'businessname' ); + $zbs_biz_yourname = zeroBSCRM_getSetting( 'businessyourname' ); + $zbs_biz_extra = zeroBSCRM_getSetting( 'businessextra' ); + $zbs_biz_youremail = zeroBSCRM_getSetting( 'businessyouremail' ); + $zbs_biz_yoururl = zeroBSCRM_getSetting( 'businessyoururl' ); // build msg-content html - $bodyHTML = $placeholder_templating->replace_placeholders( array( 'global', 'quote', 'contact' ), $bodyHTML, $replacements, array( ZBS_TYPE_QUOTE => $quote, ZBS_TYPE_CONTACT => $quote_contact ) ); + $bodyHTML = $placeholder_templating->replace_placeholders( + array( 'global', 'quote', 'contact' ), + $bodyHTML, + $replacements, + array( + ZBS_TYPE_QUOTE => $quote, + ZBS_TYPE_CONTACT => $quote_contact, + ) + ); // For now, use this, ripped from invoices: // (We need to centralise) - $bizInfoTable = '

' . $zbs_biz_name . '
' . $zbs_biz_yourname . '
'; + $bizInfoTable = '
'; $bizInfoTable .= ''; $bizInfoTable .= ''; $bizInfoTable .= ''; @@ -518,7 +527,7 @@ function zeroBSCRM_quote_generateAcceptNotifHTML( $quoteID = -1, $quoteSignedBy // $bizInfoTable .= ''; $bizInfoTable .= ''; $bizInfoTable .= '
' . $zbs_biz_name . '
' . $zbs_biz_yourname . '
'.$zbs_biz_yoururl.'
'; - + // unsub line $unsub_line = __( 'You have received this notification because your proposal has been accepted in CRM', 'zero-bs-crm' ); ##WLREMOVE @@ -527,11 +536,11 @@ function zeroBSCRM_quote_generateAcceptNotifHTML( $quoteID = -1, $quoteSignedBy $unsub_line .= __( '. If you believe this was sent in error, please reply and let us know.', 'zero-bs-crm' ); // build body html - $replacements = $placeholder_templating->get_generic_replacements(); - $replacements['title'] = $proposalEmailTitle; - $replacements['msg-content'] = $bodyHTML; - $replacements['unsub-line'] = $unsub_line; - $replacements['biz-info'] = $bizInfoTable; + $replacements = $placeholder_templating->get_generic_replacements(); + $replacements['title'] = $proposalEmailTitle; + $replacements['msg-content'] = $bodyHTML; + $replacements['unsub-line'] = $unsub_line; + $replacements['biz-info'] = $bizInfoTable; $replacements['quote-url'] = zeroBSCRM_portal_linkObj( $quoteID, ZBS_TYPE_QUOTE ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $replacements['quote-edit-url'] = jpcrm_esc_link( 'edit', $quoteID, 'zerobs_quote' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase $replacements['quote-value'] = $quote['value'] ? zeroBSCRM_formatCurrency( $quote['value'] ) : ''; @@ -545,13 +554,12 @@ function zeroBSCRM_quote_generateAcceptNotifHTML( $quoteID = -1, $quoteSignedBy } // return - if ( !$return ) { + if ( ! $return ) { echo $html; exit( 0 ); } - } return $html; @@ -562,19 +570,19 @@ function zeroBSCRM_quote_generateAcceptNotifHTML( $quoteID = -1, $quoteSignedBy return; } -/* ====================================================== +/* +====================================================== / ZBS Quotes - Generate HTML (notification email) - ====================================================== */ - + ====================================================== */ - -/* ====================================================== +/* +====================================================== ZBS Invoices - Generate HTML (notification emails) - ====================================================== */ + ====================================================== */ function zeroBSCRM_invoice_generateNotificationHTML( $invoiceID = -1, $return = true ) { - if ( !empty( $invoiceID ) && $invoiceID > 0 ) { + if ( ! empty( $invoiceID ) && $invoiceID > 0 ) { global $zbs; $invoice = $zbs->DAL->invoices->getInvoice( $invoiceID ); @@ -584,14 +592,14 @@ function zeroBSCRM_invoice_generateNotificationHTML( $invoiceID = -1, $return = // body template $mailTemplate = zeroBSCRM_mailTemplate_get( ZBSEMAIL_EMAILINVOICE ); - $bodyHTML = $mailTemplate->zbsmail_body; + $bodyHTML = $mailTemplate->zbsmail_body; // html template $html = jpcrm_retrieve_template( 'emails/default-email.html', false ); $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $html ); // Act - if ( !empty( $html ) ) { + if ( ! empty( $html ) ) { // this was refactored as was duplicate code. // now all wired through zeroBSCRM_invoicing_generateInvoiceHTML @@ -604,13 +612,12 @@ function zeroBSCRM_invoice_generateNotificationHTML( $invoiceID = -1, $return = $html = $placeholder_templating->replace_placeholders( array( 'global', 'invoice' ), $html, $replacements, array( ZBS_TYPE_INVOICE => $invoice ) ); // return - if ( !$return ) { + if ( ! $return ) { echo $html; exit( 0 ); } - } return $html; @@ -621,13 +628,12 @@ function zeroBSCRM_invoice_generateNotificationHTML( $invoiceID = -1, $return = return; } - // generates statement email html based on template in sys mail function zeroBSCRM_statement_generateNotificationHTML( $contact_id = -1, $return = true ) { global $zbs; - if ( !empty( $contact_id ) ) { + if ( ! empty( $contact_id ) ) { $contact = $zbs->DAL->contacts->getContact( $contact_id ); $pWrap = '

'; @@ -639,23 +645,23 @@ function zeroBSCRM_statement_generateNotificationHTML( $contact_id = -1, $return // body template $mailTemplate = zeroBSCRM_mailTemplate_get( ZBSEMAIL_STATEMENT ); - $bodyHTML = $mailTemplate->zbsmail_body; + $bodyHTML = $mailTemplate->zbsmail_body; // html template $html = jpcrm_retrieve_template( 'emails/default-email.html', false ); $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $html ); // Act - if ( !empty( $html ) ) { + if ( ! empty( $html ) ) { // the business info from the settings - $zbs_biz_name = zeroBSCRM_getSetting( 'businessname' ); + $zbs_biz_name = zeroBSCRM_getSetting( 'businessname' ); $zbs_biz_yourname = zeroBSCRM_getSetting( 'businessyourname' ); - $zbs_biz_extra = zeroBSCRM_getSetting( 'businessextra' ); + $zbs_biz_extra = zeroBSCRM_getSetting( 'businessextra' ); // For now, use this, ripped from invoices: // (We need to centralise) - $bizInfoTable = ''; + $bizInfoTable = '
'; $bizInfoTable .= ''; $bizInfoTable .= ''; $bizInfoTable .= ''; @@ -667,20 +673,19 @@ function zeroBSCRM_statement_generateNotificationHTML( $contact_id = -1, $return $replacements = $placeholder_templating->get_generic_replacements(); // view in portal? - $replacements['title'] = __( 'Statement', 'zero-bs-crm' ); + $replacements['title'] = __( 'Statement', 'zero-bs-crm' ); $replacements['biz-info'] = $bizInfoTable; // replacements $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact' ), $html, $replacements, array( ZBS_TYPE_CONTACT => $contact ) ); // return - if ( !$return ) { + if ( ! $return ) { echo $html; exit( 0 ); } - } return $html; @@ -689,13 +694,15 @@ function zeroBSCRM_statement_generateNotificationHTML( $contact_id = -1, $return // FAIL return; } -/* ====================================================== +/* +====================================================== / ZBS Invoices - Generate HTML (notification email) - ====================================================== */ + ====================================================== */ -/* ====================================================== +/* +====================================================== ZBS Portal - Generate HTML (notification emails) - ====================================================== */ + ====================================================== */ function zeroBSCRM_Portal_generateNotificationHTML( $pwd = -1, $return = true, $email = null, $contact_id = false ) { @@ -703,7 +710,7 @@ function zeroBSCRM_Portal_generateNotificationHTML( $pwd = -1, $return = true, $ if ( ! empty( $pwd ) ) { - $html = ''; + $html = ''; $pWrap = '

'; // Get templated notify email @@ -713,12 +720,12 @@ function zeroBSCRM_Portal_generateNotificationHTML( $pwd = -1, $return = true, $ $placeholder_templating = $zbs->get_templating(); // Act - if ( !empty( $templatedHTML ) ) { + if ( ! empty( $templatedHTML ) ) { // body $message_content = zeroBSCRM_mailTemplate_get( ZBSEMAIL_CLIENTPORTALWELCOME ); - $bodyHTML = $message_content->zbsmail_body; - $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $templatedHTML ); + $bodyHTML = $message_content->zbsmail_body; + $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $templatedHTML ); // get replacements $replacements = $placeholder_templating->get_generic_replacements(); @@ -737,13 +744,12 @@ function zeroBSCRM_Portal_generateNotificationHTML( $pwd = -1, $return = true, $ $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact' ), $html, $replacements, $replacement_objects ); // return - if ( !$return ) { + if ( ! $return ) { echo $html; exit( 0 ); } - } return $html; @@ -754,14 +760,14 @@ function zeroBSCRM_Portal_generateNotificationHTML( $pwd = -1, $return = true, $ return; } - #} adapted from above. pw reset email +#} adapted from above. pw reset email function zeroBSCRM_Portal_generatePWresetNotificationHTML( $pwd, $return, $contact ) { global $zbs; - if ( !empty( $pwd ) ) { + if ( ! empty( $pwd ) ) { - $html = ''; + $html = ''; $pWrap = '

'; // Get templated notify email @@ -771,36 +777,34 @@ function zeroBSCRM_Portal_generatePWresetNotificationHTML( $pwd, $return, $conta $placeholder_templating = $zbs->get_templating(); // Act - if ( !empty( $templatedHTML ) ) { + if ( ! empty( $templatedHTML ) ) { $message_content = zeroBSCRM_mailTemplate_get( ZBSEMAIL_CLIENTPORTALPWREST ); - $bodyHTML = $message_content->zbsmail_body; - $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $templatedHTML ); + $bodyHTML = $message_content->zbsmail_body; + $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $templatedHTML ); // get replacements $replacements = $placeholder_templating->get_generic_replacements(); // replacements - $replacements['title'] = __( 'Your Client Portal Password has been reset', 'zero-bs-crm' ); - $replacements['email'] = $contact['email']; + $replacements['title'] = __( 'Your Client Portal Password has been reset', 'zero-bs-crm' ); + $replacements['email'] = $contact['email']; $replacements['password'] = $pwd; // replacements $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact' ), $html, $replacements, array( ZBS_TYPE_CONTACT => $contact ) ); // return - if ( !$return ) { + if ( ! $return ) { echo $html; exit( 0 ); } - } return $html; - } // FAIL @@ -812,7 +816,7 @@ function jpcrm_task_generate_notification_html( $return = true, $email = false, global $zbs; // checks - if ( !zeroBSCRM_validateEmail( $email ) || $task_id < 1 ) { + if ( ! zeroBSCRM_validateEmail( $email ) || $task_id < 1 ) { return false; } @@ -820,33 +824,33 @@ function jpcrm_task_generate_notification_html( $return = true, $email = false, $templatedHTML = jpcrm_retrieve_template( 'emails/default-email.html', false ); // prep - $html = ''; + $html = ''; $pWrap = '

'; // load templater $placeholder_templating = $zbs->get_templating(); // Act - if ( !empty( $templatedHTML ) ) { + if ( ! empty( $templatedHTML ) ) { // retrieve task notification $message_content = zeroBSCRM_mailTemplate_get( ZBSEMAIL_TASK_NOTIFICATION ); - $bodyHTML = $message_content->zbsmail_body; - $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $templatedHTML ); + $bodyHTML = $message_content->zbsmail_body; + $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $templatedHTML ); // get replacements $replacements = $placeholder_templating->get_generic_replacements(); // retrieve task (if not passed) - if ( !is_array( $task ) ) { + if ( ! is_array( $task ) ) { $task = $zbs->DAL->events->getEvent( $task_id ); } // vars / html gen - $task_url = jpcrm_esc_link( 'edit', $task['id'], ZBS_TYPE_TASK ); - $task_html = '

' . nl2br( $task['desc'] ) . '

'; + $task_url = jpcrm_esc_link( 'edit', $task['id'], ZBS_TYPE_TASK ); + $task_html = '

' . nl2br( $task['desc'] ) . '

'; $task_html .= '

'; $task_html .= __( 'Your task starts at ', 'zero-bs-crm' ) . '' . $task['start_date'] . '
'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase // $task_html .= __( 'to: ', 'zero-bs-crm' ) . $task['end_date']; @@ -869,14 +873,14 @@ function jpcrm_task_generate_notification_html( $return = true, $email = false, $html, $replacements, array( - ZBS_TYPE_TASK => $task, + ZBS_TYPE_TASK => $task, ZBS_TYPE_CONTACT => isset( $task['contact'] ) ? $task['contact'][0] : null, ZBS_TYPE_COMPANY => isset( $task['company'] ) ? $task['company'][0] : null, ) ); // return - if ( !$return ) { + if ( ! $return ) { echo $html; exit( 0 ); @@ -885,50 +889,49 @@ function jpcrm_task_generate_notification_html( $return = true, $email = false, } return $html; - } - - -/* ====================================================== +/* +====================================================== / ZBS Invoices - Generate HTML (notification emails) - ====================================================== */ + ====================================================== */ - -/* ====================================================== +/* +====================================================== ZBS Single Send Emails - Generate HTML - ====================================================== */ + ====================================================== */ /** * Creates the html of a single send email based on passed details * Note this diverges from jpcrm_mailTemplates_generic_msg because it takes in $contact_object - * ... and makes sense to have it's own abstraction in any case (as later we can apply specific theming etc.) + * ... and makes sense to have it's own abstraction in any case (as later we can apply specific theming etc.) * Replaces zeroBSCRM_mailTemplates_directMsg */ -function jpcrm_mailTemplates_single_send_templated( $return=true, $content='', $title = '', $contact_object = false ){ +function jpcrm_mailTemplates_single_send_templated( $return = true, $content = '', $title = '', $contact_object = false ) { global $zbs; - $html = ''; $pWrap = '

'; + $html = ''; + $pWrap = '

'; // load templater $placeholder_templating = $zbs->get_templating(); - // Get templated notify email + // Get templated notify email $templatedHTML = jpcrm_retrieve_template( 'emails/default-email.html', false ); - // Act - if (!empty($templatedHTML)){ + // Act + if ( ! empty( $templatedHTML ) ) { - // replacements (initial templating) - $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $content, $templatedHTML ); + // replacements (initial templating) + $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $content, $templatedHTML ); - // get replacements - $replacements = $placeholder_templating->get_generic_replacements(); - $replacements['title'] = $title; + // get replacements + $replacements = $placeholder_templating->get_generic_replacements(); + $replacements['title'] = $title; - // enact replacements - $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact', 'company' ), $html, $replacements, array( ZBS_TYPE_CONTACT => $contact_object ) ); + // enact replacements + $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact', 'company' ), $html, $replacements, array( ZBS_TYPE_CONTACT => $contact_object ) ); // return if ( ! $return ) { @@ -938,38 +941,40 @@ function jpcrm_mailTemplates_single_send_templated( $return=true, $content='', $ } return $html; } -/* ====================================================== +/* +====================================================== / ZBS Single Send Emails - Generate HTML - ====================================================== */ - + ====================================================== */ -/* ====================================================== +/* +====================================================== ZBS Generic Emails - Generate HTML - ====================================================== */ -function jpcrm_mailTemplates_generic_msg($return=true, $content='', $title = ''){ + ====================================================== */ +function jpcrm_mailTemplates_generic_msg( $return = true, $content = '', $title = '' ) { global $zbs; - $html = ''; $pWrap = '

'; + $html = ''; + $pWrap = '

'; // load templater $placeholder_templating = $zbs->get_templating(); - // Get templated notify email + // Get templated notify email $templatedHTML = jpcrm_retrieve_template( 'emails/default-email.html', false ); - // Act - if (!empty($templatedHTML)){ + // Act + if ( ! empty( $templatedHTML ) ) { - // replacements (initial templating) - $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $content, $templatedHTML ); + // replacements (initial templating) + $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $content, $templatedHTML ); - // get replacements - $replacements = $placeholder_templating->get_generic_replacements(); - $replacements['title'] = $title; + // get replacements + $replacements = $placeholder_templating->get_generic_replacements(); + $replacements['title'] = $title; - // replacements - $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact', 'company' ), $html, $replacements ); + // replacements + $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact', 'company' ), $html, $replacements ); // return if ( ! $return ) { @@ -979,56 +984,56 @@ function jpcrm_mailTemplates_generic_msg($return=true, $content='', $title = '') } return $html; } -/* ====================================================== +/* +====================================================== / ZBS Generic Emails - Generate HTML - ====================================================== */ + ====================================================== */ +/* +====================================================== + ZBS Mail Delivery Tests + ====================================================== */ +function zeroBSCRM_mailDelivery_generateTestHTML( $return = true ) { -/* ====================================================== - ZBS Mail Delivery Tests - ====================================================== */ + global $zbs; + $html = ''; + $pWrap = '

'; - function zeroBSCRM_mailDelivery_generateTestHTML($return=true){ + // load templater + $placeholder_templating = $zbs->get_templating(); - global $zbs; - - $html = ''; $pWrap = '

'; + // Get templated notify email + $templatedHTML = jpcrm_retrieve_template( 'emails/default-email.html', false ); - // load templater - $placeholder_templating = $zbs->get_templating(); + #} Act + if ( ! empty( $templatedHTML ) ) { - // Get templated notify email - $templatedHTML = jpcrm_retrieve_template( 'emails/default-email.html', false ); + #} Actual body: + $bodyHTML = ''; - #} Act - if (!empty($templatedHTML)){ - - #} Actual body: - $bodyHTML = ''; + $bodyHTML = "

" . __( 'Testing Mail Delivery Option', 'zero-bs-crm' ) . '

'; + $bodyHTML .= '

' . __( "This is a test email, sent to you by Jetpack CRM. If you're receiving this loud and clear, it means your mail delivery setup has been successful, congratulations!", 'zero-bs-crm' ) . '

'; - $bodyHTML = "

".__('Testing Mail Delivery Option',"zero-bs-crm")."

"; - $bodyHTML .= '

'.__("This is a test email, sent to you by Jetpack CRM. If you're receiving this loud and clear, it means your mail delivery setup has been successful, congratulations!","zero-bs-crm").'

'; - - ##WLREMOVE - $bodyHTML .= '

'.__("Why not follow us on twitter to celebrate?","zero-bs-crm").'

'; - $bodyHTML .= '

@jetpackcrm

'; - ##/WLREMOVE + ##WLREMOVE + $bodyHTML .= '

' . __( 'Why not follow us on twitter to celebrate?', 'zero-bs-crm' ) . '

'; + $bodyHTML .= '

@jetpackcrm

'; + ##/WLREMOVE - $bodyHTML .= "
"; + $bodyHTML .= '
'; - // replacements (initial templating) - $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $templatedHTML ); + // replacements (initial templating) + $html = $placeholder_templating->replace_single_placeholder( 'msg-content', $bodyHTML, $templatedHTML ); - // get replacements - $replacements = $placeholder_templating->get_generic_replacements(); - $replacements['title'] = __( 'Testing Mail Delivery Option', 'zero-bs-crm' ); - $replacements['biz-info'] = '

'.__( "Sent from your friendly neighbourhood CRM.", "zero-bs-crm" ).'

'; - $replacements['unsub-line'] = '

'.__( "Have a great day.", "zero-bs-crm" ).'

'; + // get replacements + $replacements = $placeholder_templating->get_generic_replacements(); + $replacements['title'] = __( 'Testing Mail Delivery Option', 'zero-bs-crm' ); + $replacements['biz-info'] = '

' . __( 'Sent from your friendly neighbourhood CRM.', 'zero-bs-crm' ) . '

'; + $replacements['unsub-line'] = '

' . __( 'Have a great day.', 'zero-bs-crm' ) . '

'; - // replacements - $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact', 'company' ), $html, $replacements ); + // replacements + $html = $placeholder_templating->replace_placeholders( array( 'global', 'contact', 'company' ), $html, $replacements ); // return if ( ! $return ) { @@ -1039,19 +1044,17 @@ function zeroBSCRM_mailDelivery_generateTestHTML($return=true){ return $html; } - -/* ====================================================== +/* +====================================================== / ZBS Mail Delivery Tests - ====================================================== */ + ====================================================== */ - - - -/* ====================================================== +/* +====================================================== ZBS Mail Templating General - ====================================================== */ + ====================================================== */ -function zeroBSCRM_mailTemplate_poweredByHTML( $type='html' ) { +function zeroBSCRM_mailTemplate_poweredByHTML( $type = 'html' ) { ##WLREMOVE global $zbs; @@ -1068,79 +1071,74 @@ function zeroBSCRM_mailTemplate_poweredByHTML( $type='html' ) { return __( 'Powered by Jetpack CRM', 'zero-bs-crm' ); } - } ##/WLREMOVE return ''; } +function zeroBSCRM_mailTemplate_getHeaders( $templateID = -1 ) { -function zeroBSCRM_mailTemplate_getHeaders($templateID = -1){ + if ( $templateID > 0 ) { - if($templateID > 0){ + $mailTemplate = zeroBSCRM_mailTemplate_get( $templateID ); - $mailTemplate = zeroBSCRM_mailTemplate_get($templateID); + // headers being set... + $headers = array( 'Content-Type: text/html; charset=UTF-8' ); - //headers being set... - $headers = array('Content-Type: text/html; charset=UTF-8'); - - //extra header settings.. + // extra header settings.. // We don't use these now, as mail is sent out properly via Mail Delivery - //$headers[] = 'From: '. esc_html($mailTemplate->zbsmail_fromname).' <'.sanitize_email($mailTemplate->zbsmail_fromaddress).'>'; - //$headers[] = 'Reply-To: ' . sanitize_email($mailTemplate->zbsmail_replyto); - // but we use this :) - if (isset($mailTemplate->zbsmail_bccto) && !empty($mailTemplate->zbsmail_bccto)) $headers[] = 'Bcc: ' . sanitize_email($mailTemplate->zbsmail_bccto); - - - }else{ - $headers = array('Content-Type: text/html; charset=UTF-8'); + // $headers[] = 'From: '. esc_html($mailTemplate->zbsmail_fromname).' <'.sanitize_email($mailTemplate->zbsmail_fromaddress).'>'; + // $headers[] = 'Reply-To: ' . sanitize_email($mailTemplate->zbsmail_replyto); + // but we use this :) + if ( isset( $mailTemplate->zbsmail_bccto ) && ! empty( $mailTemplate->zbsmail_bccto ) ) { + $headers[] = 'Bcc: ' . sanitize_email( $mailTemplate->zbsmail_bccto ); + } + } else { + $headers = array( 'Content-Type: text/html; charset=UTF-8' ); } return $headers; } // adapted from https://buttons.cm/ -function zeroBSCRM_mailTemplate_emailSafeButton($url='',$str=''){ +function zeroBSCRM_mailTemplate_emailSafeButton( $url = '', $str = '' ) { return ''; - } - // replaces generic attrs in one place, e.g. loginlink, loginurl -// note as placeholder templates hard-override empty placeholders not passed, +// note as placeholder templates hard-override empty placeholders not passed, // here we pass true as the forth variable to leave existing ##PLACEHOLDERS## intact // (if leave_existing_placeholders = true) // // TL;DR; Phase out using this function, instead get the replacements for use with 'replace_placeholders' // ... from ->get_generic_replacements() -function zeroBSCRM_mailTemplate_genericReplaces( $html='', $leave_existing_placeholders = true ){ +function zeroBSCRM_mailTemplate_genericReplaces( $html = '', $leave_existing_placeholders = true ) { global $zbs; // load templater - $placeholder_templating = $zbs->get_templating(); - - // get replacements - $replacements = $placeholder_templating->get_generic_replacements(); + $placeholder_templating = $zbs->get_templating(); - // replace - return $placeholder_templating->replace_placeholders( array( 'global' ), $html, $replacements, $leave_existing_placeholders ); + // get replacements + $replacements = $placeholder_templating->get_generic_replacements(); + // replace + return $placeholder_templating->replace_placeholders( array( 'global' ), $html, $replacements, $leave_existing_placeholders ); } - -/* ====================================================== +/* +====================================================== / ZBS Mail Templating General - ====================================================== */ + ====================================================== */ diff --git a/projects/plugins/crm/includes/jpcrm-segment-conditions.php b/projects/plugins/crm/includes/jpcrm-segment-conditions.php index 16943dce9095..cc502e4e7bc1 100644 --- a/projects/plugins/crm/includes/jpcrm-segment-conditions.php +++ b/projects/plugins/crm/includes/jpcrm-segment-conditions.php @@ -1,5 +1,5 @@ - array( - 'name' => __( 'Status', 'zero-bs-crm' ), - 'category' => __( 'Contact Fields', 'zero-bs-crm' ), - 'position' => 1, - 'description' => __( 'Select contacts based on their status', 'zero-bs-crm' ), - 'operators' => array( 'equal', 'notequal'), - 'fieldname' => 'status' - ), - 'fullname' => array( - 'name' => __( 'Full Name', 'zero-bs-crm' ), - 'category' => __( 'Contact Fields', 'zero-bs-crm' ), - 'position' => 1, - 'description' => __( 'Select contacts based on their full name ', 'zero-bs-crm' ), - 'operators' => array( 'equal', 'notequal', 'contains' ), 'fieldname' => 'fullname' - ), - 'email' => array( - 'name' => __( 'Email', 'zero-bs-crm' ), - 'category' => __( 'Contact Fields', 'zero-bs-crm' ), - 'position' => 1, - 'description' => __( 'Select contacts based on their email address', 'zero-bs-crm' ), - 'operators' => array( 'equal', 'notequal', 'contains' ), - 'fieldname' => 'email' - ), - 'dateadded' => array( - 'name' => __( 'Date Added', 'zero-bs-crm' ), - 'category' => __( 'Contact Fields', 'zero-bs-crm' ), - 'description' => __( 'Select contacts by when they were added to the CRM', 'zero-bs-crm' ), - 'operators' => array( 'before', 'after', 'daterange', 'datetimerange', 'beforeequal', 'afterequal', 'previousdays' ), - 'fieldname' => 'dateadded', - 'conversion' => 'date-to-uts' - ), - 'datelastcontacted' => array( - 'name' => __( 'Date Last Contacted', 'zero-bs-crm' ), - 'category' => __( 'Contact Fields', 'zero-bs-crm' ), - 'description' => __( 'Select contacts by the date that they were last contacted', 'zero-bs-crm' ), - 'operators' => array( 'before', 'after', 'daterange', 'datetimerange', 'beforeequal', 'afterequal', 'previousdays' ), - 'fieldname' => 'datelastcontacted', - 'conversion' => 'date-to-uts' - ), - 'tagged' => array( - 'name' => __( 'Has Tag', 'zero-bs-crm' ), - 'category' => __( 'Contact Fields', 'zero-bs-crm' ), - 'description' => __( 'Select Contacts who have a specific tag', 'zero-bs-crm' ), - 'operators' => array( 'tag' ), - 'fieldname' => 'tagged' - ), - 'nottagged' => array( - 'name' => __( 'Is Not Tagged', 'zero-bs-crm' ), - 'category' => __( 'Contact Fields', 'zero-bs-crm' ), - 'description' => __( 'Select contacts who do not have a specific tag', 'zero-bs-crm' ), - 'operators' => array( 'tag' ), - 'fieldname' => 'nottagged' - ), - - ); -} + return array( + 'status' => array( + 'name' => __( 'Status', 'zero-bs-crm' ), + 'category' => __( 'Contact Fields', 'zero-bs-crm' ), + 'position' => 1, + 'description' => __( 'Select contacts based on their status', 'zero-bs-crm' ), + 'operators' => array( 'equal', 'notequal' ), + 'fieldname' => 'status', + ), + 'fullname' => array( + 'name' => __( 'Full Name', 'zero-bs-crm' ), + 'category' => __( 'Contact Fields', 'zero-bs-crm' ), + 'position' => 1, + 'description' => __( 'Select contacts based on their full name ', 'zero-bs-crm' ), + 'operators' => array( 'equal', 'notequal', 'contains' ), + 'fieldname' => 'fullname', + ), + 'email' => array( + 'name' => __( 'Email', 'zero-bs-crm' ), + 'category' => __( 'Contact Fields', 'zero-bs-crm' ), + 'position' => 1, + 'description' => __( 'Select contacts based on their email address', 'zero-bs-crm' ), + 'operators' => array( 'equal', 'notequal', 'contains' ), + 'fieldname' => 'email', + ), + 'dateadded' => array( + 'name' => __( 'Date Added', 'zero-bs-crm' ), + 'category' => __( 'Contact Fields', 'zero-bs-crm' ), + 'description' => __( 'Select contacts by when they were added to the CRM', 'zero-bs-crm' ), + 'operators' => array( 'before', 'after', 'daterange', 'datetimerange', 'beforeequal', 'afterequal', 'previousdays' ), + 'fieldname' => 'dateadded', + 'conversion' => 'date-to-uts', + ), + 'datelastcontacted' => array( + 'name' => __( 'Date Last Contacted', 'zero-bs-crm' ), + 'category' => __( 'Contact Fields', 'zero-bs-crm' ), + 'description' => __( 'Select contacts by the date that they were last contacted', 'zero-bs-crm' ), + 'operators' => array( 'before', 'after', 'daterange', 'datetimerange', 'beforeequal', 'afterequal', 'previousdays' ), + 'fieldname' => 'datelastcontacted', + 'conversion' => 'date-to-uts', + ), + 'tagged' => array( + 'name' => __( 'Has Tag', 'zero-bs-crm' ), + 'category' => __( 'Contact Fields', 'zero-bs-crm' ), + 'description' => __( 'Select Contacts who have a specific tag', 'zero-bs-crm' ), + 'operators' => array( 'tag' ), + 'fieldname' => 'tagged', + ), + 'nottagged' => array( + 'name' => __( 'Is Not Tagged', 'zero-bs-crm' ), + 'category' => __( 'Contact Fields', 'zero-bs-crm' ), + 'description' => __( 'Select contacts who do not have a specific tag', 'zero-bs-crm' ), + 'operators' => array( 'tag' ), + 'fieldname' => 'nottagged', + ), + + ); +} /* * Returns segment condition category positions (to effect the display order) */ function jpcrm_segments_condition_category_positions() { - global $zbs; + global $zbs; - return apply_filters( 'jpcrm_segment_condition_category_positions', array( + return apply_filters( + 'jpcrm_segment_condition_category_positions', + array( - $zbs->DAL->makeSlug( __( 'Contact Fields', 'zero-bs-crm' ) ) => 1, - $zbs->DAL->makeSlug( __( 'Contact Address Fields', 'zero-bs-crm' ) ) => 2, - $zbs->DAL->makeSlug( __( 'Quotes', 'zero-bs-crm' ) ) => 3, - $zbs->DAL->makeSlug( __( 'Invoices', 'zero-bs-crm' ) ) => 4, - $zbs->DAL->makeSlug( __( 'Transactions', 'zero-bs-crm' ) ) => 5, - $zbs->DAL->makeSlug( __( 'Source', 'zero-bs-crm' ) ) => 6, - $zbs->DAL->makeSlug( __( 'Ownership', 'zero-bs-crm' ) ) => 7, + $zbs->DAL->makeSlug( __( 'Contact Fields', 'zero-bs-crm' ) ) => 1, + $zbs->DAL->makeSlug( __( 'Contact Address Fields', 'zero-bs-crm' ) ) => 2, + $zbs->DAL->makeSlug( __( 'Quotes', 'zero-bs-crm' ) ) => 3, + $zbs->DAL->makeSlug( __( 'Invoices', 'zero-bs-crm' ) ) => 4, + $zbs->DAL->makeSlug( __( 'Transactions', 'zero-bs-crm' ) ) => 5, + $zbs->DAL->makeSlug( __( 'Source', 'zero-bs-crm' ) ) => 6, + $zbs->DAL->makeSlug( __( 'Ownership', 'zero-bs-crm' ) ) => 7, - 'general' => 99 // end of list - - )); + 'general' => 99, // end of list + ) + ); } - /* * Retrieves available segment conditions */ -function zeroBSCRM_segments_availableConditions( $split_by_category = false ){ +function zeroBSCRM_segments_availableConditions( $split_by_category = false ) { - global $zbs; + global $zbs; - // retrieve conditions - $available_conditions = apply_filters('zbs_segment_conditions', jpcrm_segments_default_conditions() ); - - // compare with previous available conditions - // (fires jpcrm_segment_conditions_changed action if changes in available conditions) - // Note that we only fire this if it's not already been fired on this load (to avoid looping) - if ( !defined( 'jpcrm_segments_compared' ) ) { + // retrieve conditions + $available_conditions = apply_filters( 'zbs_segment_conditions', jpcrm_segments_default_conditions() ); - // blocker. This is a prime candidate for core states (#XXX) - define( 'jpcrm_segments_compared', 1 ); + // compare with previous available conditions + // (fires jpcrm_segment_conditions_changed action if changes in available conditions) + // Note that we only fire this if it's not already been fired on this load (to avoid looping) + if ( ! defined( 'jpcrm_segments_compared' ) ) { - // compare - jpcrm_segments_compare_available_conditions_to_prev( $available_conditions ); + // blocker. This is a prime candidate for core states (#XXX) + define( 'jpcrm_segments_compared', 1 ); - } + // compare + jpcrm_segments_compare_available_conditions_to_prev( $available_conditions ); - // if not split by category, return as it was - if ( !$split_by_category ){ + } - return $available_conditions; + // if not split by category, return as it was + if ( ! $split_by_category ) { - } + return $available_conditions; - // else, split by category, so build that and return: - $category_positions = jpcrm_segments_condition_category_positions(); + } + + // else, split by category, so build that and return: + $category_positions = jpcrm_segments_condition_category_positions(); $conditions_by_category = array( 'general' => array( - 'name' => __( 'General', 'zero-bs-crm' ), - 'conditions' => array(), - 'position' => 99 - ) + 'name' => __( 'General', 'zero-bs-crm' ), + 'conditions' => array(), + 'position' => 99, + ), ); - foreach ( $available_conditions as $key => $condition ){ + foreach ( $available_conditions as $key => $condition ) { - if ( isset( $condition['category'] ) ){ + if ( isset( $condition['category'] ) ) { - $category = $zbs->DAL->makeSlug( $condition['category'] ); + $category = $zbs->DAL->makeSlug( $condition['category'] ); $category_position = 99; // to enact category positions, we see if the category has a position, if so we use that as a prefix - if ( isset( $category_positions[ $category ] ) ){ - + if ( isset( $category_positions[ $category ] ) ) { + $category_position = $category_positions[ $category ]; } // if not set, create it - if ( !isset( $conditions_by_category[ $category ] ) ){ + if ( ! isset( $conditions_by_category[ $category ] ) ) { $conditions_by_category[ $category ] = array( 'key' => $category, 'name' => $condition['category'], 'conditions' => array(), - 'position' => $category_position + 'position' => $category_position, ); } - - } else $category = 'general'; + } else { + $category = 'general'; + } // add condition $conditions_by_category[ $category ]['conditions'][ $key ] = $condition; @@ -174,50 +175,45 @@ function zeroBSCRM_segments_availableConditions( $split_by_category = false ){ } // sort categories - usort( $conditions_by_category, 'jpcrm_segments_sort_conditions_and_categories'); + usort( $conditions_by_category, 'jpcrm_segments_sort_conditions_and_categories' ); // in turn sort each conditions sub-list by position $conditions_by_category_array = array(); - foreach ( $conditions_by_category as $category_key => $category ){ + foreach ( $conditions_by_category as $category_key => $category ) { $conditions = $category['conditions']; - usort( $conditions, 'jpcrm_segments_sort_conditions_and_categories'); + usort( $conditions, 'jpcrm_segments_sort_conditions_and_categories' ); - $conditions_by_category_array[ $category_key ] = $category; + $conditions_by_category_array[ $category_key ] = $category; $conditions_by_category_array[ $category_key ]['conditions'] = $conditions; } - ksort( $conditions_by_category_array ); return $conditions_by_category_array; - - } -/* +/* * Sorting function for categories and conditions */ -function jpcrm_segments_sort_conditions_and_categories($a, $b){ +function jpcrm_segments_sort_conditions_and_categories( $a, $b ) { $position_a = 99; $position_b = 99; - if ( isset( $a['position'] ) ){ + if ( isset( $a['position'] ) ) { $position_a = $a['position']; } - if ( isset( $b['position'] ) ){ + if ( isset( $b['position'] ) ) { $position_b = $b['position']; } - return $position_a < $position_b ? -1 : ($position_a == $position_b ? 0 : 1); - + return $position_a < $position_b ? -1 : ( $position_a == $position_b ? 0 : 1 ); } - -function zeroBSCRM_segments_availableConditionOperators(){ +function zeroBSCRM_segments_availableConditionOperators() { return array( @@ -243,64 +239,57 @@ function zeroBSCRM_segments_availableConditionOperators(){ 'lessequal' => array( 'name' => __( 'Less than or equal to (<=)', 'zero-bs-crm' ) ), ); - } - /* * Compares available segment conditions to previously logged available conditions * Fires `jpcrm_segment_conditions_changed` action if change observed. -* +* * @param array $available_conditions - segment conditions available */ -function jpcrm_segments_compare_available_conditions_to_prev( $available_conditions = false ){ +function jpcrm_segments_compare_available_conditions_to_prev( $available_conditions = false ) { - global $zbs; + global $zbs; + // if not passed, retrieve + if ( ! $available_conditions ) { - // if not passed, retrieve - if ( !$available_conditions ){ - - // retrieve conditions - $available_conditions = apply_filters('zbs_segment_conditions', jpcrm_segments_default_conditions() ); + // retrieve conditions + $available_conditions = apply_filters( 'zbs_segment_conditions', jpcrm_segments_default_conditions() ); - } - - // retrieve previous hash - $previous_conditions_hash = $zbs->settings->get( 'segment-condition-hash' ); + } - // generate new - $available_conditions_hash = jpcrm_generate_hash_of_obj( $available_conditions ); - - // if different, conditions available have changed, so regenerate segment audiences - if ( $available_conditions_hash != $previous_conditions_hash ){ + // retrieve previous hash + $previous_conditions_hash = $zbs->settings->get( 'segment-condition-hash' ); - // fire action which can be hooked into to check segments for errors - // e.g. if using advanced segments or custom code to add custom conditions - // ... then that code is removed/deactivated, therefor you lose access to conditions - do_action( 'jpcrm_segment_conditions_changed' ); + // generate new + $available_conditions_hash = jpcrm_generate_hash_of_obj( $available_conditions ); - // save hash - $zbs->settings->update( 'segment-condition-hash', $available_conditions_hash ); + // if different, conditions available have changed, so regenerate segment audiences + if ( $available_conditions_hash != $previous_conditions_hash ) { - } + // fire action which can be hooked into to check segments for errors + // e.g. if using advanced segments or custom code to add custom conditions + // ... then that code is removed/deactivated, therefor you lose access to conditions + do_action( 'jpcrm_segment_conditions_changed' ); + // save hash + $zbs->settings->update( 'segment-condition-hash', $available_conditions_hash ); + } } - /* * Segment conditions available have changed, let's rebuild segment counts * (which inadvertantly checks for segments where conditions are no longer present) * * Fired on `jpcrm_segment_conditions_changed`. */ -function jpcrm_segments_conditions_have_changed(){ - - global $zbs; +function jpcrm_segments_conditions_have_changed() { - // recompile all segments - $zbs->DAL->segments->compile_all_segments(); + global $zbs; + // recompile all segments + $zbs->DAL->segments->compile_all_segments(); } -add_action('jpcrm_segment_conditions_changed', 'jpcrm_segments_conditions_have_changed'); +add_action( 'jpcrm_segment_conditions_changed', 'jpcrm_segments_conditions_have_changed' ); diff --git a/projects/plugins/crm/includes/jpcrm-templating-placeholders.php b/projects/plugins/crm/includes/jpcrm-templating-placeholders.php index 757471a7bd42..63d8dbddc5dc 100644 --- a/projects/plugins/crm/includes/jpcrm-templating-placeholders.php +++ b/projects/plugins/crm/includes/jpcrm-templating-placeholders.php @@ -1,5 +1,5 @@ - 'Contact ID', - 'origin' => 'Contact Object model', - 'replace_str' => '##CONTACT-ID##', - 'aliases' => array('##CID##'), + 'description' => 'Contact ID', + 'origin' => 'Contact Object model', + 'replace_str' => '##CONTACT-ID##', + 'aliases' => array('##CID##'), 'associated_type' => ZBS_TYPE_CONTACT, 'expected_format' => 'str' // future proofing - 'available_in' => array( - + 'available_in' => array( + // tooling allowed to use this, from: // if specified, otherwise areas may use type to identify which placeholders are available 'system_email_templates', @@ -43,13 +42,13 @@ */ /** -* jpcrm_templating_placeholders is the placeholder layer in Jetpack CRM 4+ -* -* @author Woody Hayday -* @version 4.0 -* @access public -* @see https://kb.jetpackcrm.com -*/ + * jpcrm_templating_placeholders is the placeholder layer in Jetpack CRM 4+ + * + * @author Woody Hayday + * @version 4.0 + * @access public + * @see https://kb.jetpackcrm.com + */ class jpcrm_templating_placeholders { // default set of placeholders, to get amended on init (Custom fields etc.) @@ -57,39 +56,37 @@ class jpcrm_templating_placeholders { // stores common links e.g. contact fields in quotes // for now these repreresent the 1:1 relational links in the db - // later, as the DAL is extended, this could take advantage of + // later, as the DAL is extended, this could take advantage of // a better mapping integral to the DAL, perhaps extending // the $linkedToObjectTypes system. // for now it's an exception, so hard-typing: private $available_in_links = array( - 'contact' => array( - 'quote', - 'invoice', - 'transaction', - 'event' - ), - 'company' => array( - // 'quote', - 'invoice', - 'transaction', - 'event' - ) + 'contact' => array( + 'quote', + 'invoice', + 'transaction', + 'event', + ), + 'company' => array( + // 'quote', + 'invoice', + 'transaction', + 'event', + ), ); // =============================================================================== // =========== INIT ============================================================= - function __construct($args=array()) { + function __construct( $args = array() ) { // Build out list of placeholders $this->build_placeholders(); - } // =========== / INIT =========================================================== // =============================================================================== - /** * Fills out default placeholders * This is executed on init because we want to include the full translatable strings @@ -97,57 +94,57 @@ function __construct($args=array()) { * * @return array of all placeholders */ - private function default_placeholders(){ + private function default_placeholders() { $this->placeholders = array( // CRM global placeholders, e.g. business name (from settings) - 'global' => array( + 'global' => array( - 'biz-name' => array( + 'biz-name' => array( - 'description' => __( 'Business name', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Business name', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'str', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##BIZ-NAME##', - 'aliases' => array( '###BIZNAME###', '##BIZNAME##' ) + 'replace_str' => '##BIZ-NAME##', + 'aliases' => array( '###BIZNAME###', '##BIZNAME##' ), ), - 'biz-state' => array( + 'biz-state' => array( - 'description' => __( 'Business state', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Business state', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'str', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##BIZ-STATE##', - 'aliases' => array( '##BIZSTATE##' ) + 'replace_str' => '##BIZ-STATE##', + 'aliases' => array( '##BIZSTATE##' ), ), - 'biz-logo' => array( + 'biz-logo' => array( - 'description' => __( 'Business logo', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Business logo', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##BIZ-LOGO##' + 'replace_str' => '##BIZ-LOGO##', ), - 'biz-info' => array( + 'biz-info' => array( - 'description' => __( 'Table with your business information (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => false, - 'replace_str' => '##BIZ-INFO##', - 'aliases' => array( '###BIZINFOTABLE###', '###BIZ-INFO###', '###FOOTERBIZDEETS###', '##INVOICE-BIZ-INFO##' ) + 'description' => __( 'Table with your business information (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => false, + 'replace_str' => '##BIZ-INFO##', + 'aliases' => array( '###BIZINFOTABLE###', '###BIZ-INFO###', '###FOOTERBIZDEETS###', '##INVOICE-BIZ-INFO##' ), ), - 'biz-your-name' => array( + 'biz-your-name' => array( 'description' => __( 'Business: Your Name', 'zero-bs-crm' ), 'origin' => __( 'Global', 'zero-bs-crm' ), @@ -158,7 +155,7 @@ private function default_placeholders(){ 'aliases' => array(), ), - 'biz-your-email' => array( + 'biz-your-email' => array( 'description' => __( 'Business: Your Email', 'zero-bs-crm' ), 'origin' => __( 'Global', 'zero-bs-crm' ), @@ -169,7 +166,7 @@ private function default_placeholders(){ 'aliases' => array(), ), - 'biz-your-url' => array( + 'biz-your-url' => array( 'description' => __( 'Business: Your URL', 'zero-bs-crm' ), 'origin' => __( 'Global', 'zero-bs-crm' ), @@ -191,666 +188,658 @@ private function default_placeholders(){ 'aliases' => array(), ), - 'social-links' => array( + 'social-links' => array( - 'description' => __( 'Social links', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Social links', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##SOCIAL-LINKS##' + 'replace_str' => '##SOCIAL-LINKS##', ), - 'unsub-line' => array( + 'unsub-line' => array( - 'description' => __( 'Unsubscribe line', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Unsubscribe line', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##UNSUB-LINE##', - 'aliases' => array( '###UNSUB-LINE###', '###UNSUB###', '###UNSUBSCRIBE###', '###FOOTERUNSUBDEETS###' ) + 'replace_str' => '##UNSUB-LINE##', + 'aliases' => array( '###UNSUB-LINE###', '###UNSUB###', '###UNSUBSCRIBE###', '###FOOTERUNSUBDEETS###' ), ), - 'powered-by' => array( + 'powered-by' => array( - 'description' => __( 'Powered by', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Powered by', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##POWERED-BY##', - 'aliases' => array( '###POWEREDBYDEETS###' ) + 'replace_str' => '##POWERED-BY##', + 'aliases' => array( '###POWEREDBYDEETS###' ), ), - 'login-link' => array( + 'login-link' => array( - 'description' => __( 'CRM login link (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'CRM login link (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##LOGIN-LINK##', - 'aliases' => array( '###LOGINLINK###' ) + 'replace_str' => '##LOGIN-LINK##', + 'aliases' => array( '###LOGINLINK###' ), ), - 'login-button' => array( + 'login-button' => array( - 'description' => __( 'CRM login link button (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'CRM login link button (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##LOGIN-BUTTON##', - 'aliases' => array( '###LOGINBUTTON###' ) + 'replace_str' => '##LOGIN-BUTTON##', + 'aliases' => array( '###LOGINBUTTON###' ), ), - 'login-url' => array( + 'login-url' => array( - 'description' => __( 'CRM login URL', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'CRM login URL', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'str', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##LOGIN-URL##', - 'aliases' => array( '###LOGINURL###', '###ADMINURL###' ) + 'replace_str' => '##LOGIN-URL##', + 'aliases' => array( '###LOGINURL###', '###ADMINURL###' ), ), - 'portal-link' => array( + 'portal-link' => array( - 'description' => __( 'Portal link (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Portal link (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##PORTAL-LINK##', - 'aliases' => array( '###PORTALLINK###' ) + 'replace_str' => '##PORTAL-LINK##', + 'aliases' => array( '###PORTALLINK###' ), ), 'portal-view-button' => array( - 'description' => __( '"View in Portal" button (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( '"View in Portal" button (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##PORTAL-VIEW-BUTTON##', - 'aliases' => array( '###VIEWINPORTAL###' ) + 'replace_str' => '##PORTAL-VIEW-BUTTON##', + 'aliases' => array( '###VIEWINPORTAL###' ), ), - 'portal-button' => array( + 'portal-button' => array( - 'description' => __( 'Portal link button (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Portal link button (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##PORTAL-BUTTON##', - 'aliases' => array( '###PORTALBUTTON###' ) + 'replace_str' => '##PORTAL-BUTTON##', + 'aliases' => array( '###PORTALBUTTON###' ), ), - 'portal-url' => array( + 'portal-url' => array( - 'description' => __( 'Portal URL', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Portal URL', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'str', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##PORTAL-URL##', - 'aliases' => array( '###PORTALURL###' ) + 'replace_str' => '##PORTAL-URL##', + 'aliases' => array( '###PORTALURL###' ), ), + 'css' => array( - 'css' => array( - - 'description' => __( 'CSS (restricted to HTML templates)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'CSS (restricted to HTML templates)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##CSS##', - 'aliases' => array( '###CSS###' ) + 'replace_str' => '##CSS##', + 'aliases' => array( '###CSS###' ), ), - 'title' => array( + 'title' => array( - 'description' => __( 'Generally used to fill HTML title tags', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Generally used to fill HTML title tags', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'str', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##TITLE##', - 'aliases' => array( '###TITLE###' ) + 'replace_str' => '##TITLE##', + 'aliases' => array( '###TITLE###' ), ), - 'msg-content' => array( + 'msg-content' => array( - 'description' => __( 'Message content (restricted to some email templates)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Message content (restricted to some email templates)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'html', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##MSG-CONTENT##', - 'aliases' => array( '###MSGCONTENT###' ) + 'replace_str' => '##MSG-CONTENT##', + 'aliases' => array( '###MSGCONTENT###' ), ), - 'email' => array( + 'email' => array( - 'description' => __( 'Email (generally used to insert user email)', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Email (generally used to insert user email)', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'str', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##EMAIL##', - 'aliases' => array( '###EMAIL###' ) + 'replace_str' => '##EMAIL##', + 'aliases' => array( '###EMAIL###' ), ), - 'password' => array( + 'password' => array( - 'description' => __( 'Inserts a link where one can reset their password', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), + 'description' => __( 'Inserts a link where one can reset their password', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), 'expected_format' => 'str', - 'available_in' => array(), + 'available_in' => array(), 'associated_type' => false, - 'replace_str' => '##PASSWORD##', - 'aliases' => array( '##PASSWORD-RESET-LINK##', '###PASSWORD###' ) + 'replace_str' => '##PASSWORD##', + 'aliases' => array( '##PASSWORD-RESET-LINK##', '###PASSWORD###' ), ), - 'email-from-name' => array( + 'email-from-name' => array( - 'description' => __( '"From" Name when sending email', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), - 'expected_format' => 'email', - 'available_in' => array(), - 'associated_type' => false, - 'replace_str' => '##EMAIL-FROM-NAME##', - 'aliases' => array( '###FROMNAME###' ) + 'description' => __( '"From" Name when sending email', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), + 'expected_format' => 'email', + 'available_in' => array(), + 'associated_type' => false, + 'replace_str' => '##EMAIL-FROM-NAME##', + 'aliases' => array( '###FROMNAME###' ), ), - ), + ), - 'contact' => array( + 'contact' => array( 'contact-fullname' => array( - 'description' => __( 'Contact full name', 'zero-bs-crm' ), - 'origin' => __( 'Contact Information', 'zero-bs-crm' ), - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_CONTACT, - 'replace_str' => '##CONTACT-FULLNAME##', - 'expected_format' => 'str', - 'aliases' => array( '##CUSTOMERNAME##', '##CUSTOMER-FULLNAME##' ) + 'description' => __( 'Contact full name', 'zero-bs-crm' ), + 'origin' => __( 'Contact Information', 'zero-bs-crm' ), + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_CONTACT, + 'replace_str' => '##CONTACT-FULLNAME##', + 'expected_format' => 'str', + 'aliases' => array( '##CUSTOMERNAME##', '##CUSTOMER-FULLNAME##' ), ), ), - 'company' => array( - - ), - 'quote' => array( + 'company' => array(), + 'quote' => array( - 'quote-content' => array( + 'quote-content' => array( - 'description' => __( 'Quote content (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_QUOTE, - 'replace_str' => '##QUOTE-CONTENT##', - 'aliases' => array( '###QUOTECONTENT###' ) + 'description' => __( 'Quote content (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_QUOTE, + 'replace_str' => '##QUOTE-CONTENT##', + 'aliases' => array( '###QUOTECONTENT###' ), ), - 'quote-title' => array( + 'quote-title' => array( - 'description' => __( 'Quote title', 'zero-bs-crm' ), - 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_QUOTE, - 'replace_str' => '##QUOTE-TITLE##', - 'aliases' => array( '###QUOTETITLE###', '##QUOTETITLE##' ) + 'description' => __( 'Quote title', 'zero-bs-crm' ), + 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_QUOTE, + 'replace_str' => '##QUOTE-TITLE##', + 'aliases' => array( '###QUOTETITLE###', '##QUOTETITLE##' ), ), - 'quote-value' => array( + 'quote-value' => array( - 'description' => __( 'Quote value', 'zero-bs-crm' ), - 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_QUOTE, - 'replace_str' => '##QUOTE-VALUE##', - 'aliases' => array( '###QUOTEVALUE###', '##QUOTEVALUE##' ) + 'description' => __( 'Quote value', 'zero-bs-crm' ), + 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_QUOTE, + 'replace_str' => '##QUOTE-VALUE##', + 'aliases' => array( '###QUOTEVALUE###', '##QUOTEVALUE##' ), ), - 'quote-date' => array( + 'quote-date' => array( - 'description' => __( 'Quote date', 'zero-bs-crm' ), - 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_QUOTE, - 'replace_str' => '##QUOTE-DATE##', - 'aliases' => array( '###QUOTEDATE###', '##QUOTEDATE##' ) + 'description' => __( 'Quote date', 'zero-bs-crm' ), + 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_QUOTE, + 'replace_str' => '##QUOTE-DATE##', + 'aliases' => array( '###QUOTEDATE###', '##QUOTEDATE##' ), ), - 'quote-url' => array( + 'quote-url' => array( - 'description' => __( 'Quote URL', 'zero-bs-crm' ), - 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_QUOTE, - 'replace_str' => '##QUOTE-URL##', - 'aliases' => array( '###QUOTEURL###' ) + 'description' => __( 'Quote URL', 'zero-bs-crm' ), + 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_QUOTE, + 'replace_str' => '##QUOTE-URL##', + 'aliases' => array( '###QUOTEURL###' ), ), 'quote-edit-url' => array( - 'description' => __( 'Quote edit URL', 'zero-bs-crm' ), - 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_QUOTE, - 'replace_str' => '##QUOTE-EDIT-URL##', - 'aliases' => array( '###QUOTEEDITURL###' ) + 'description' => __( 'Quote edit URL', 'zero-bs-crm' ), + 'origin' => __( 'Quote Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_QUOTE, + 'replace_str' => '##QUOTE-EDIT-URL##', + 'aliases' => array( '###QUOTEEDITURL###' ), ), ), - 'invoice' => array( + 'invoice' => array( - 'invoice-title' => array( + 'invoice-title' => array( - 'description' => __( 'Invoice title', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-TITLE##', - 'aliases' => array( '###INVOICETITLE###' ) + 'description' => __( 'Invoice title', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-TITLE##', + 'aliases' => array( '###INVOICETITLE###' ), ), - 'logo-class' => array( + 'logo-class' => array( - 'description' => __( 'Invoice logo CSS class', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##LOGO-CLASS##', - 'aliases' => array( '###LOGOCLASS###' ) + 'description' => __( 'Invoice logo CSS class', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##LOGO-CLASS##', + 'aliases' => array( '###LOGOCLASS###' ), ), - 'logo-url' => array( + 'logo-url' => array( - 'description' => __( 'Invoice logo URL', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##LOGO-URL##', - 'aliases' => array( '###LOGOURL###' ) + 'description' => __( 'Invoice logo URL', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##LOGO-URL##', + 'aliases' => array( '###LOGOURL###' ), ), - 'invoice-number' => array( + 'invoice-number' => array( - 'description' => __( 'Invoice number', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-NUMBER##', - 'aliases' => array( '###INVNOSTR###' ) + 'description' => __( 'Invoice number', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-NUMBER##', + 'aliases' => array( '###INVNOSTR###' ), ), - 'invoice-date' => array( + 'invoice-date' => array( - 'description' => __( 'Invoice date', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-DATE##', - 'aliases' => array( '###INVDATESTR###' ) + 'description' => __( 'Invoice date', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-DATE##', + 'aliases' => array( '###INVDATESTR###' ), ), - 'invoice-id-styles' => array( + 'invoice-id-styles' => array( - 'description' => __( 'Invoice ID styles', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-ID-STYLES##', - 'aliases' => array( '###INVIDSTYLES###' ) + 'description' => __( 'Invoice ID styles', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-ID-STYLES##', + 'aliases' => array( '###INVIDSTYLES###' ), ), - 'invoice-ref' => array( + 'invoice-ref' => array( - 'description' => __( 'Invoice reference', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-REF##', - 'aliases' => array( '###REF###' ) + 'description' => __( 'Invoice reference', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-REF##', + 'aliases' => array( '###REF###' ), ), - 'invoice-due-date' => array( + 'invoice-due-date' => array( - 'description' => __( 'Invoice due date', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-DUE-DATE##', - 'aliases' => array( '###DUEDATE###' ) + 'description' => __( 'Invoice due date', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-DUE-DATE##', + 'aliases' => array( '###DUEDATE###' ), ), - 'invoice-biz-class' => array( + 'invoice-biz-class' => array( - 'description' => __( 'CSS class for table with your business info', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-BIZ-CLASS##', - 'aliases' => array( '###BIZCLASS###' ) + 'description' => __( 'CSS class for table with your business info', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-BIZ-CLASS##', + 'aliases' => array( '###BIZCLASS###' ), ), - 'invoice-customer-info' => array( + 'invoice-customer-info' => array( - 'description' => __( 'Table with assigned contact information (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-CUSTOMER-INFO##', - 'aliases' => array( '###CUSTINFOTABLE###' ) + 'description' => __( 'Table with assigned contact information (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-CUSTOMER-INFO##', + 'aliases' => array( '###CUSTINFOTABLE###' ), ), - 'invoice-from-name' => array( + 'invoice-from-name' => array( - 'description' => __( 'Name of company issuing the invoice', 'zero-bs-crm' ), - 'origin' => __( 'Statement Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-FROM-NAME##', - 'aliases' => array() + 'description' => __( 'Name of company issuing the invoice', 'zero-bs-crm' ), + 'origin' => __( 'Statement Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-FROM-NAME##', + 'aliases' => array(), ), - 'invoice-table-headers' => array( + 'invoice-table-headers' => array( - 'description' => __( 'Table headers for invoice line items (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-TABLE-HEADERS##', - 'aliases' => array( '###TABLEHEADERS###' ) + 'description' => __( 'Table headers for invoice line items (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-TABLE-HEADERS##', + 'aliases' => array( '###TABLEHEADERS###' ), ), - 'invoice-line-items' => array( + 'invoice-line-items' => array( - 'description' => __( 'Invoice line items (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-LINE-ITEMS##', - 'aliases' => array( '###LINEITEMS###' ) + 'description' => __( 'Invoice line items (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-LINE-ITEMS##', + 'aliases' => array( '###LINEITEMS###' ), ), - 'invoice-totals-table' => array( + 'invoice-totals-table' => array( - 'description' => __( 'Invoice totals table (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-TOTALS-TABLE##', - 'aliases' => array( '###TOTALSTABLE###' ) + 'description' => __( 'Invoice totals table (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-TOTALS-TABLE##', + 'aliases' => array( '###TOTALSTABLE###' ), ), 'pre-invoice-payment-details' => array( - 'description' => __( 'Text before invoice payment details', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##PRE-INVOICE-PAYMENT-DETAILS##', - 'aliases' => array( '###PREPARTIALS###' ) + 'description' => __( 'Text before invoice payment details', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##PRE-INVOICE-PAYMENT-DETAILS##', + 'aliases' => array( '###PREPARTIALS###' ), ), - 'invoice-payment-details' => array( + 'invoice-payment-details' => array( - 'description' => __( 'Invoice payment details', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-PAYMENT-DETAILS##', - 'aliases' => array( '###PAYMENTDEETS###', '###PAYDETAILS###', ) + 'description' => __( 'Invoice payment details', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-PAYMENT-DETAILS##', + 'aliases' => array( '###PAYMENTDEETS###', '###PAYDETAILS###' ), ), - 'invoice-partials-table' => array( + 'invoice-partials-table' => array( - 'description' => __( 'Invoice partials table (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-PARTIALS-TABLE##', - 'aliases' => array( '###PARTIALSTABLE###' ) + 'description' => __( 'Invoice partials table (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-PARTIALS-TABLE##', + 'aliases' => array( '###PARTIALSTABLE###' ), ), - 'invoice-label-inv-number' => array( + 'invoice-label-inv-number' => array( - 'description' => __( 'Label for invoice number', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-LABEL-INV-NUMBER##', - 'aliases' => array( '###LANGINVNO###' ) + 'description' => __( 'Label for invoice number', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-LABEL-INV-NUMBER##', + 'aliases' => array( '###LANGINVNO###' ), ), - 'invoice-label-inv-date' => array( + 'invoice-label-inv-date' => array( - 'description' => __( 'Label for invoice date', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-LABEL-INV-DATE##', - 'aliases' => array( '###LANGINVDATE###' ) + 'description' => __( 'Label for invoice date', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-LABEL-INV-DATE##', + 'aliases' => array( '###LANGINVDATE###' ), ), - 'invoice-label-inv-ref' => array( + 'invoice-label-inv-ref' => array( - 'description' => __( 'Label for invoice reference', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-LABEL-INV-REF##', - 'aliases' => array( '###LANGINVREF###' ) + 'description' => __( 'Label for invoice reference', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-LABEL-INV-REF##', + 'aliases' => array( '###LANGINVREF###' ), ), - 'invoice-label-from' => array( + 'invoice-label-from' => array( - 'description' => __( 'Label for name of company issuing invoice', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-LABEL-FROM##', - 'aliases' => array( '###LANGFROM###' ) + 'description' => __( 'Label for name of company issuing invoice', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-LABEL-FROM##', + 'aliases' => array( '###LANGFROM###' ), ), - 'invoice-label-to' => array( + 'invoice-label-to' => array( 'description' => __( 'Label for name of contact receiving invoice', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-LABEL-TO##', - 'aliases' => array( '###LANGTO###' ) + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-LABEL-TO##', + 'aliases' => array( '###LANGTO###' ), ), - 'invoice-label-due-date' => array( + 'invoice-label-due-date' => array( - 'description' => __( 'Label for invoice due date', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-LABEL-DUE-DATE##', - 'aliases' => array( '###LANGDUEDATE###' ) + 'description' => __( 'Label for invoice due date', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-LABEL-DUE-DATE##', + 'aliases' => array( '###LANGDUEDATE###' ), ), - 'invoice-label-status' => array( + 'invoice-label-status' => array( - 'description' => __( 'Label for invoice status', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-LABEL-STATUS##', - 'aliases' => array() + 'description' => __( 'Label for invoice status', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-LABEL-STATUS##', + 'aliases' => array(), ), - 'invoice-html-status' => array( + 'invoice-html-status' => array( - 'description' => __( 'Invoice status (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-HTML-STATUS##', - 'aliases' => array( '###TOPSTATUS###' ) + 'description' => __( 'Invoice status (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-HTML-STATUS##', + 'aliases' => array( '###TOPSTATUS###' ), ), - 'invoice-pay-button' => array( + 'invoice-pay-button' => array( - 'description' => __( 'Invoice pay button (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-PAY-BUTTON##', - 'aliases' => array( '###PAYPALBUTTON###' ) + 'description' => __( 'Invoice pay button (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-PAY-BUTTON##', + 'aliases' => array( '###PAYPALBUTTON###' ), ), - 'invoice-pay-thanks' => array( + 'invoice-pay-thanks' => array( - 'description' => __( 'Invoice payment thanks message (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-PAY-THANKS##', - 'aliases' => array( '###PAYTHANKS###' ) + 'description' => __( 'Invoice payment thanks message (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-PAY-THANKS##', + 'aliases' => array( '###PAYTHANKS###' ), ), - 'invoice-pay-terms' => array( + 'invoice-pay-terms' => array( - 'description' => __( 'Invoice payment terms (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-PAY-TERMS##', - 'aliases' => array( '###PAYMENTTERMS###' ) + 'description' => __( 'Invoice payment terms (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-PAY-TERMS##', + 'aliases' => array( '###PAYMENTTERMS###' ), ), - 'invoice-statement-html' => array( + 'invoice-statement-html' => array( - 'description' => __( 'Invoice statement (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Statement Builder', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-STATEMENT-HTML##', - 'aliases' => array( '###STATEMENTHTML###' ) + 'description' => __( 'Invoice statement (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Statement Builder', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-STATEMENT-HTML##', + 'aliases' => array( '###STATEMENTHTML###' ), ), - 'invoice-ref-styles' => array( + 'invoice-ref-styles' => array( - 'description' => __( 'CSS attributes applied to invoice reference label', 'zero-bs-crm' ), - 'origin' => __( 'Statement Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INVOICE-REF-STYLES##', - 'aliases' => array( '###INVREFSTYLES###' ) + 'description' => __( 'CSS attributes applied to invoice reference label', 'zero-bs-crm' ), + 'origin' => __( 'Statement Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INVOICE-REF-STYLES##', + 'aliases' => array( '###INVREFSTYLES###' ), ), - 'invoice-custom-fields' => array( + 'invoice-custom-fields' => array( - 'description' => __( 'Any custom fields associated with invoice (if enabled in Invoice Settings)', 'zero-bs-crm' ), - 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_INVOICE, - 'replace_str' => '##INV-CUSTOM-FIELDS##', - 'aliases' => array() + 'description' => __( 'Any custom fields associated with invoice (if enabled in Invoice Settings)', 'zero-bs-crm' ), + 'origin' => __( 'Invoice Builder', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_INVOICE, + 'replace_str' => '##INV-CUSTOM-FIELDS##', + 'aliases' => array(), ), - - - ), - 'transaction' => array( - ), - 'event' => array( + 'transaction' => array(), + 'event' => array( - 'task-title' => array( + 'task-title' => array( - 'description' => __( 'Task title', 'zero-bs-crm' ), - 'origin' => __( 'Task Scheduler', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_TASK, - 'replace_str' => '##TASK-TITLE##', - 'aliases' => array( '###EVENTTITLE###', '##EVENT-TITLE##' ) + 'description' => __( 'Task title', 'zero-bs-crm' ), + 'origin' => __( 'Task Scheduler', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_TASK, + 'replace_str' => '##TASK-TITLE##', + 'aliases' => array( '###EVENTTITLE###', '##EVENT-TITLE##' ), ), - 'task-link' => array( + 'task-link' => array( - 'description' => __( 'Task link (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Task Scheduler', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_TASK, - 'replace_str' => '##TASK-LINK##', - 'aliases' => array( '###EVENTLINK###' ) + 'description' => __( 'Task link (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Task Scheduler', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_TASK, + 'replace_str' => '##TASK-LINK##', + 'aliases' => array( '###EVENTLINK###' ), ), 'task-link-button' => array( - 'description' => __( 'Task link button (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Task Scheduler', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_TASK, - 'replace_str' => '##TASK-LINK-BUTTON##', - 'aliases' => array( '###EVENTLINKBUTTON###' ) + 'description' => __( 'Task link button (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Task Scheduler', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_TASK, + 'replace_str' => '##TASK-LINK-BUTTON##', + 'aliases' => array( '###EVENTLINKBUTTON###' ), ), - 'task-body' => array( + 'task-body' => array( - 'description' => __( 'Task content (HTML)', 'zero-bs-crm' ), - 'origin' => __( 'Task Scheduler', 'zero-bs-crm' ), - 'expected_format' => 'html', - 'available_in' => array(), - 'associated_type' => ZBS_TYPE_TASK, - 'replace_str' => '##TASK-BODY##', - 'aliases' => array( '###EVENTBODY###' ) + 'description' => __( 'Task content (HTML)', 'zero-bs-crm' ), + 'origin' => __( 'Task Scheduler', 'zero-bs-crm' ), + 'expected_format' => 'html', + 'available_in' => array(), + 'associated_type' => ZBS_TYPE_TASK, + 'replace_str' => '##TASK-BODY##', + 'aliases' => array( '###EVENTBODY###' ), ), - ), // probably not req. yet: @@ -867,16 +856,14 @@ private function default_placeholders(){ ); return $this->placeholders; - } - /** * Builds initial list of placeholders using defaults, object-models, custom fields, and filters * * @return array of all placeholders */ - public function build_placeholders( $include_custom_fields = true ){ + public function build_placeholders( $include_custom_fields = true ) { global $zbs; @@ -887,9 +874,15 @@ public function build_placeholders( $include_custom_fields = true ){ $placeholders = $this->load_from_object_models( $placeholders, $include_custom_fields ); // some backward compat tweaks: - if ( isset( $placeholders['quote']['title'] ) ) $placeholders['quote']['title']['aliases'] = array( '##QUOTE-TITLE##', '##QUOTETITLE##' ); - if ( isset( $placeholders['quote']['value'] ) ) $placeholders['quote']['value']['aliases'] = array( '##QUOTEVALUE##' ); - if ( isset( $placeholders['quote']['date'] ) ) $placeholders['quote']['date']['aliases'] = array( '##QUOTEDATE##' ); + if ( isset( $placeholders['quote']['title'] ) ) { + $placeholders['quote']['title']['aliases'] = array( '##QUOTE-TITLE##', '##QUOTETITLE##' ); + } + if ( isset( $placeholders['quote']['value'] ) ) { + $placeholders['quote']['value']['aliases'] = array( '##QUOTEVALUE##' ); + } + if ( isset( $placeholders['quote']['date'] ) ) { + $placeholders['quote']['date']['aliases'] = array( '##QUOTEDATE##' ); + } // add setting dependent placeholders $placeholders = $this->add_setting_dependent_placeholders( $placeholders ); @@ -903,16 +896,14 @@ public function build_placeholders( $include_custom_fields = true ){ // return return $this->placeholders; - } - /** * Add setting-dependent placeholders * * @return array of all placeholders */ - public function add_setting_dependent_placeholders( $placeholders = array() ){ + public function add_setting_dependent_placeholders( $placeholders = array() ) { // remove tooling where inactive modules $placeholders = $this->strip_inactive_tooling( $placeholders ); @@ -921,136 +912,120 @@ public function add_setting_dependent_placeholders( $placeholders = array() ){ // this is simplistic for now and appears outwardly to only encompasses contacts // ... in fact it works for all object types (provided the object is passed to replace_placeholders()) // as per #1531 this could later be expanded to encompass all objects, perhaps in sites & teams extension - $using_ownership = zeroBSCRM_getSetting( 'perusercustomers' ); - if ( $using_ownership ){ + $using_ownership = zeroBSCRM_getSetting( 'perusercustomers' ); + if ( $using_ownership ) { - if ( isset( $placeholders['global'] ) ){ + if ( isset( $placeholders['global'] ) ) { // note, these are auto-populated using the first `owner` field that our replacement function comes across in $replacement_objects $placeholders['global']['assigned-to-name'] = array( - 'description' => __( 'Where available, the display name of the WordPress user who owns the object', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), - 'expected_format' => 'str', - 'available_in' => array(), - 'associated_type' => false, - 'replace_str' => '##ASSIGNED-TO-NAME##', - 'aliases' => array( '##ASSIGNED-TO-SIGNATURE##' ) + 'description' => __( 'Where available, the display name of the WordPress user who owns the object', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), + 'expected_format' => 'str', + 'available_in' => array(), + 'associated_type' => false, + 'replace_str' => '##ASSIGNED-TO-NAME##', + 'aliases' => array( '##ASSIGNED-TO-SIGNATURE##' ), ); $placeholders['global']['assigned-to-email'] = array( - 'description' => __( 'Where available, the email of the WordPress user who owns the object', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), - 'expected_format' => 'email', - 'available_in' => array(), - 'associated_type' => false, - 'replace_str' => '##ASSIGNED-TO-EMAIL##', - 'aliases' => array() + 'description' => __( 'Where available, the email of the WordPress user who owns the object', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), + 'expected_format' => 'email', + 'available_in' => array(), + 'associated_type' => false, + 'replace_str' => '##ASSIGNED-TO-EMAIL##', + 'aliases' => array(), ); $placeholders['global']['assigned-to-username'] = array( - 'description' => __( 'Where available, the username of the WordPress user who owns the object', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), - 'expected_format' => 'email', - 'available_in' => array(), - 'associated_type' => false, - 'replace_str' => '##ASSIGNED-TO-USERNAME##', - 'aliases' => array() + 'description' => __( 'Where available, the username of the WordPress user who owns the object', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), + 'expected_format' => 'email', + 'available_in' => array(), + 'associated_type' => false, + 'replace_str' => '##ASSIGNED-TO-USERNAME##', + 'aliases' => array(), ); - $placeholders['global']['assigned-to-mob'] = array( + $placeholders['global']['assigned-to-mob'] = array( - 'description' => __( 'Where available, the mobile phone of the WordPress user who owns the object', 'zero-bs-crm' ), - 'origin' => __( 'Global', 'zero-bs-crm' ), - 'expected_format' => 'tel', - 'available_in' => array(), - 'associated_type' => false, - 'replace_str' => '##ASSIGNED-TO-MOB##', - 'aliases' => array() + 'description' => __( 'Where available, the mobile phone of the WordPress user who owns the object', 'zero-bs-crm' ), + 'origin' => __( 'Global', 'zero-bs-crm' ), + 'expected_format' => 'tel', + 'available_in' => array(), + 'associated_type' => false, + 'replace_str' => '##ASSIGNED-TO-MOB##', + 'aliases' => array(), ); - } - } - return $placeholders; - } - /** * Remove object types where that module is not active, e.g. invoices * This needs to fire before this->add_available_in in the build queue * * @return array of all placeholders */ - public function strip_inactive_tooling( $placeholders = array() ){ + public function strip_inactive_tooling( $placeholders = array() ) { $setting_map = array( - 'form' => 'feat_forms', - 'quote' => 'feat_quotes', - 'invoice' => 'feat_invs', - 'event' => 'feat_calendar', - 'transaction' => 'feat_transactions', + 'form' => 'feat_forms', + 'quote' => 'feat_quotes', + 'invoice' => 'feat_invs', + 'event' => 'feat_calendar', + 'transaction' => 'feat_transactions', ); // make a quick state list for simplicity $tooling_states = array(); - foreach ( $setting_map as $tooling_area => $setting_key ){ - - $tooling_states[ $tooling_area ] = (zeroBSCRM_getSetting( $setting_key ) == "1") ? true : false; + foreach ( $setting_map as $tooling_area => $setting_key ) { + $tooling_states[ $tooling_area ] = ( zeroBSCRM_getSetting( $setting_key ) == '1' ) ? true : false; // remove from placeholder list - if ( !$tooling_states[ $tooling_area ] && isset( $placeholders[ $tooling_area ] ) ){ + if ( ! $tooling_states[ $tooling_area ] && isset( $placeholders[ $tooling_area ] ) ) { // remove unset( $placeholders[ $tooling_area ] ); - } - + } } - // remove from $available_in_links too $available_in = array(); - foreach ( $this->available_in_links as $object_type_key => $tooling_area_array ){ + foreach ( $this->available_in_links as $object_type_key => $tooling_area_array ) { - if ( !isset( $tooling_states[ $object_type_key ] ) || $tooling_states[ $object_type_key ] ){ + if ( ! isset( $tooling_states[ $object_type_key ] ) || $tooling_states[ $object_type_key ] ) { $tooling_available = array(); - foreach ( $tooling_area_array as $tooling_area ){ + foreach ( $tooling_area_array as $tooling_area ) { // add back if not in the list - if ( !array_key_exists( $tooling_area, $tooling_states) || $tooling_states[ $tooling_area ] ){ + if ( ! array_key_exists( $tooling_area, $tooling_states ) || $tooling_states[ $tooling_area ] ) { $tooling_available[] = $tooling_area; } - } $available_in[ $object_type_key ] = $tooling_available; } - - } $this->available_in_links = $available_in; // return return $placeholders; - } - - - - /** * Appends to passed placeholder model based on DAL object models * (optionally) including custom fields where applicable @@ -1060,49 +1035,69 @@ public function strip_inactive_tooling( $placeholders = array() ){ * @return int count */ private function load_from_object_models( - $placeholders, + $placeholders, $include_custom_fields = false, $excluded_slugs = array( // global - 'zbs_site', 'zbs_team', 'zbs_owner', 'id_override', 'parent', 'send_attachments', 'hash', + 'zbs_site', + 'zbs_team', + 'zbs_owner', + 'id_override', + 'parent', + 'send_attachments', + 'hash', // contact 'alias', - // quote - 'template', 'acceptedsigned', 'acceptedip', + // quote + 'template', + 'acceptedsigned', + 'acceptedip', // invoice - 'pay_via', 'allow_tip', 'allow_partial', 'hash_viewed', 'hash_viewed_count', 'portal_viewed', 'portal_viewed_count', 'pdf_template', 'portal_template', 'email_template', 'invoice_frequency', 'address_to_objtype', + 'pay_via', + 'allow_tip', + 'allow_partial', + 'hash_viewed', + 'hash_viewed_count', + 'portal_viewed', + 'portal_viewed_count', + 'pdf_template', + 'portal_template', + 'email_template', + 'invoice_frequency', + 'address_to_objtype', // event - 'show_on_cal', 'show_on_portal', 'title', - - ) + 'show_on_cal', + 'show_on_portal', + 'title', - ){ + ) + ) { global $zbs; // retrieve object types - $object_types = $zbs->DAL->get_object_types_by_index(); + $object_types = $zbs->DAL->get_object_types_by_index(); $second_address_label = zeroBSCRM_getSetting( 'secondaddresslabel' ); if ( empty( $second_address_label ) ) { $second_address_label = __( 'Second Address', 'zero-bs-crm' ); } // cycle through them, adding where they have $include_in_templating - foreach ( $object_types as $object_type_index => $object_type_key ){ + foreach ( $object_types as $object_type_index => $object_type_key ) { $object_layer = $zbs->DAL->getObjectLayerByType( $object_type_index ); $object_label = $zbs->DAL->typeStr( $object_type_index ); // if there is an object layer available, and it's included in templating: - if ( is_object( $object_layer ) && $object_layer->is_included_in_templating() ){ + if ( is_object( $object_layer ) && $object_layer->is_included_in_templating() ) { // (optionally) include custom field references - if ( $include_custom_fields ){ + if ( $include_custom_fields ) { $object_model = $object_layer->objModelIncCustomFields(); @@ -1116,7 +1111,7 @@ private function load_from_object_models( foreach ( $object_model as $field_index => $field_info ) { // deal with exclusions - if ( !in_array( $field_index, $excluded_slugs ) ) { + if ( ! in_array( $field_index, $excluded_slugs ) ) { // catching legacy secondary address contact field issues $secondary_address_array = array( 'secaddr1', 'secaddr2', 'seccity', 'seccounty', 'secpostcode', 'seccountry' ); @@ -1131,7 +1126,7 @@ private function load_from_object_models( // add if not present // e.g. $placeholders['contact']['ID'] - if ( !isset( $placeholders[ $object_type_key ][ $new_key ] ) ) { + if ( ! isset( $placeholders[ $object_type_key ][ $new_key ] ) ) { // prettify these $description = $object_label . ' ' . $field_index; @@ -1165,7 +1160,7 @@ private function load_from_object_models( $description = $object_label . ' ' . __( $field_info['label'], 'zero-bs-crm' ); } - if ( !empty( $field_info['area'] ) && $field_info['area'] == 'Second Address' ) { + if ( ! empty( $field_info['area'] ) && $field_info['area'] == 'Second Address' ) { $description .= ' (' . esc_html( $second_address_label ) . ')'; } @@ -1217,21 +1212,15 @@ private function load_from_object_models( ); } } - } - } - } - } } return $placeholders; - } - /** * Adds `available_in` links to allow tooling to get all applicable fields * e.g. Contact fields will be available in Quote builder @@ -1240,82 +1229,73 @@ private function load_from_object_models( * * @return array $placeholders placeholder array */ - private function add_available_in( $placeholders ){ + private function add_available_in( $placeholders ) { // any to add? - if ( is_array( $this->available_in_links ) ){ + if ( is_array( $this->available_in_links ) ) { - foreach ( $this->available_in_links as $object_type => $tooling_area_array ){ + foreach ( $this->available_in_links as $object_type => $tooling_area_array ) { // $object_type = 'contact', $tooling_area = where to point to - if ( isset( $placeholders[ $object_type ] ) ){ + if ( isset( $placeholders[ $object_type ] ) ) { - foreach ( $placeholders[ $object_type ] as $object_type_placeholder_key => $object_type_placeholder ){ + foreach ( $placeholders[ $object_type ] as $object_type_placeholder_key => $object_type_placeholder ) { // setup if not set - if ( !is_array( $placeholders[ $object_type ][ $object_type_placeholder_key ]['available_in'] ) ){ + if ( ! is_array( $placeholders[ $object_type ][ $object_type_placeholder_key ]['available_in'] ) ) { $placeholders[ $object_type ][ $object_type_placeholder_key ]['available_in'] = array(); } // add if not present - foreach ( $tooling_area_array as $tooling_area){ + foreach ( $tooling_area_array as $tooling_area ) { - if ( !in_array( $tooling_area, $placeholders[ $object_type ][ $object_type_placeholder_key ]['available_in'] )){ + if ( ! in_array( $tooling_area, $placeholders[ $object_type ][ $object_type_placeholder_key ]['available_in'] ) ) { $placeholders[ $object_type ][ $object_type_placeholder_key ]['available_in'][] = $tooling_area; } - } - } - } - } - } return $placeholders; - } /** * Returns full list of viable placeholders - * + * * @param bool separate_categories - return in multi-dim array split out by categories * * @return array of all placeholders */ - public function get_placeholders( $separate_categories = true ){ + public function get_placeholders( $separate_categories = true ) { global $zbs; // if asked to return without categories, do that - if ( !$separate_categories ){ + if ( ! $separate_categories ) { $no_cat_list = array(); - foreach ( $this->placeholders as $placeholder_group_key => $placeholder_group ){ + foreach ( $this->placeholders as $placeholder_group_key => $placeholder_group ) { - foreach ( $placeholder_group as $placeholder_key => $placeholder ){ + foreach ( $placeholder_group as $placeholder_key => $placeholder ) { $no_cat_list[ $placeholder['replace_str'] ] = $placeholder; // any aliases too if ( isset( $placeholder['aliases'] ) && is_array( $placeholder['aliases'] ) ) { - foreach ( $placeholder['aliases'] as $alias ){ + foreach ( $placeholder['aliases'] as $alias ) { $no_cat_list[ $alias ] = $placeholder; } - } - } - } return $no_cat_list; @@ -1323,21 +1303,19 @@ public function get_placeholders( $separate_categories = true ){ } return $this->placeholders; - } - /** * Returns flattened list of viable placeholders * * @return array of all placeholders */ - public function get_placeholders_shorthand(){ + public function get_placeholders_shorthand() { global $zbs; $shorthand_list = array(); - foreach ( $this->placeholders as $placeholder_group_key => $placeholder_group ){ + foreach ( $this->placeholders as $placeholder_group_key => $placeholder_group ) { $placeholder_group_prefix = ''; @@ -1348,30 +1326,25 @@ public function get_placeholders_shorthand(){ } - foreach ( $placeholder_group as $placeholder_key => $placeholder ){ + foreach ( $placeholder_group as $placeholder_key => $placeholder ) { $shorthand_list[] = '##' . strtoupper( $placeholder_group_prefix . $placeholder_key ) . '##'; // any aliases too if ( isset( $placeholder['aliases'] ) && is_array( $placeholder['aliases'] ) ) { - foreach ( $placeholder['aliases'] as $alias ){ + foreach ( $placeholder['aliases'] as $alias ) { $shorthand_list[] = $alias; } - } - } - } return $shorthand_list; - } - /** * Returns list of viable placeholders for specific tooling/area, or group of areas, or object types, e.g. system emails or contact * @@ -1381,14 +1354,16 @@ public function get_placeholders_shorthand(){ * * @return array placeholders */ - public function get_placeholders_for_tooling( $tooling = array('global'), $hydrate_aliases = false, $split_by_category = false ){ + public function get_placeholders_for_tooling( $tooling = array( 'global' ), $hydrate_aliases = false, $split_by_category = false ) { global $zbs; $applicable_placeholders = array(); // we allow array or string input here, so if a string, wrap for below - if ( is_string( $tooling ) ) $tooling = array( $tooling ); + if ( is_string( $tooling ) ) { + $tooling = array( $tooling ); + } // for MVP we let this get the whole lot then filter down, if this proves unperformant we could optimise here // .. or cache. @@ -1396,9 +1371,9 @@ public function get_placeholders_for_tooling( $tooling = array('global'), $hydra // cycle through all looking at the `available_in` attribute. // alternatively if an object type is passed, it'll return all fields for that type - if ( is_array( $placeholders ) ){ + if ( is_array( $placeholders ) ) { - foreach ( $placeholders as $placeholder_group_key => $placeholder_group ){ + foreach ( $placeholders as $placeholder_group_key => $placeholder_group ) { $placeholder_group_prefix = ''; @@ -1409,19 +1384,18 @@ public function get_placeholders_for_tooling( $tooling = array('global'), $hydra } - foreach ( $placeholder_group as $placeholder_key => $placeholder ){ + foreach ( $placeholder_group as $placeholder_key => $placeholder ) { // if in object type group: - if ( - in_array( $placeholder_group_key, $tooling ) + if ( in_array( $placeholder_group_key, $tooling ) || - isset( $placeholder['available_in'] ) && count( array_intersect( $tooling, $placeholder['available_in']) ) > 0 - ){ + isset( $placeholder['available_in'] ) && count( array_intersect( $tooling, $placeholder['available_in'] ) ) > 0 + ) { // here we've flattened the array to actual placeholders (no tooling group) // so use the placeholder str as key and add original id to array $key = '##' . strtoupper( $placeholder_group_prefix . $placeholder_key ) . '##'; - if ( isset( $placeholder['replace_str'] ) ){ + if ( isset( $placeholder['replace_str'] ) ) { // this overrides if set (will always be the same?) $key = $placeholder['replace_str']; @@ -1429,9 +1403,9 @@ public function get_placeholders_for_tooling( $tooling = array('global'), $hydra } // if return in categories - if ( $split_by_category ){ + if ( $split_by_category ) { - if ( !isset( $applicable_placeholders[ $placeholder_group_key ] ) || !is_array( $applicable_placeholders[ $placeholder_group_key ] ) ){ + if ( ! isset( $applicable_placeholders[ $placeholder_group_key ] ) || ! is_array( $applicable_placeholders[ $placeholder_group_key ] ) ) { $applicable_placeholders[ $placeholder_group_key ] = array(); @@ -1440,24 +1414,24 @@ public function get_placeholders_for_tooling( $tooling = array('global'), $hydra $applicable_placeholders[ $placeholder_group_key ][ $key ] = $placeholder; // add original key to arr - $applicable_placeholders[ $placeholder_group_key ][ $key ]['key'] = $placeholder_key; + $applicable_placeholders[ $placeholder_group_key ][ $key ]['key'] = $placeholder_key; } else { $applicable_placeholders[ $key ] = $placeholder; // add original key to arr - $applicable_placeholders[ $key ]['key'] = $placeholder_key; + $applicable_placeholders[ $key ]['key'] = $placeholder_key; } // aliases if ( $hydrate_aliases && isset( $placeholder['aliases'] ) && is_array( $placeholder['aliases'] ) ) { - foreach ( $placeholder['aliases'] as $alias ){ + foreach ( $placeholder['aliases'] as $alias ) { // if return in categories - if ( $split_by_category ){ + if ( $split_by_category ) { $applicable_placeholders[ $placeholder_group_key ][ $alias ] = $placeholder; @@ -1466,26 +1440,16 @@ public function get_placeholders_for_tooling( $tooling = array('global'), $hydra $applicable_placeholders[ $alias ] = $placeholder; } - } - } - } - } - } - - } return $applicable_placeholders; - } - - /** * Returns a single placeholder info array based on a key * @@ -1493,34 +1457,31 @@ public function get_placeholders_for_tooling( $tooling = array('global'), $hydra * * @return array placeholder info */ - public function get_single_placeholder_info( $placeholder = '' ){ + public function get_single_placeholder_info( $placeholder = '' ) { // cycle through placeholders and return our match - foreach ( $this->placeholders as $placeholder_area => $placeholders ){ + foreach ( $this->placeholders as $placeholder_area => $placeholders ) { - foreach ( $placeholders as $key => $placeholder_info ){ + foreach ( $placeholders as $key => $placeholder_info ) { - if ( $key == $placeholder ){ + if ( $key == $placeholder ) { return $placeholder_info; } - } - } return false; - } /* * Returns a template-friendly placeholder array of generic replacements */ - public function get_generic_replacements(){ + public function get_generic_replacements() { global $zbs; - + // vars $login_url = admin_url( 'admin.php?page=' . $zbs->slugs['dash'] ); $portal_url = zeroBS_portal_link(); @@ -1540,19 +1501,19 @@ public function get_generic_replacements(){ ) ); $social_links = show_social_links(); - + // return return array( // login - 'login-link' => '' . __( 'Go to CRM', 'zero-bs-crm' ) . '', - 'login-button' => '
'.zeroBSCRM_mailTemplate_emailSafeButton( $login_url, __( 'Go to CRM', 'zero-bs-crm' ) ).'
', - 'login-url' => $login_url, + 'login-link' => '' . __( 'Go to CRM', 'zero-bs-crm' ) . '', + 'login-button' => '
' . zeroBSCRM_mailTemplate_emailSafeButton( $login_url, __( 'Go to CRM', 'zero-bs-crm' ) ) . '
', + 'login-url' => $login_url, // portal - 'portal-link' => '' . $portal_url . '', - 'portal-button' => '
'.zeroBSCRM_mailTemplate_emailSafeButton( $portal_url, __( 'View Portal', 'zero-bs-crm' ) ).'
', - 'portal-url' => $portal_url, + 'portal-link' => '' . $portal_url . '', + 'portal-button' => '
' . zeroBSCRM_mailTemplate_emailSafeButton( $portal_url, __( 'View Portal', 'zero-bs-crm' ) ) . '
', + 'portal-url' => $portal_url, // biz stuff 'biz-name' => $biz_name, @@ -1564,14 +1525,13 @@ public function get_generic_replacements(){ 'biz-logo' => jpcrm_business_logo_img( '150px' ), // general - 'powered-by' => zeroBSCRM_mailTemplate_poweredByHTML(), - 'email-from-name' => zeroBSCRM_mailDelivery_defaultFromname(), - 'password' => ''. __('Set Your Password', 'zero-bs-crm').'', + 'powered-by' => zeroBSCRM_mailTemplate_poweredByHTML(), + 'email-from-name' => zeroBSCRM_mailDelivery_defaultFromname(), + 'password' => '' . __( 'Set Your Password', 'zero-bs-crm' ) . '', // social 'social-links' => $social_links, ); - } /** @@ -1585,7 +1545,7 @@ public function get_generic_replacements(){ * * @return string modified string */ - public function replace_single_placeholder( $placeholder_key = '', $replace_with = '', $string = '' ){ + public function replace_single_placeholder( $placeholder_key = '', $replace_with = '', $string = '' ) { // get info $placeholder_info = $this->get_single_placeholder_info( $placeholder_key ); @@ -1595,9 +1555,9 @@ public function replace_single_placeholder( $placeholder_key = '', $replace_with // auto-gen $main_placeholder_key = $this->make_placeholder_str( $placeholder_key ); - + // if replace_str is set, use that - if ( isset( $placeholder_info['replace_str'] ) ){ + if ( isset( $placeholder_info['replace_str'] ) ) { $main_placeholder_key = $placeholder_info['replace_str']; @@ -1606,32 +1566,29 @@ public function replace_single_placeholder( $placeholder_key = '', $replace_with // replace any and all variants (e.g. aliases) // we do these first, as often in our case the variants are backward-compat // and so `###BIZ-INFO###` needs replacing before `##BIZ-INFO##` - if ( isset( $placeholder_info['aliases'] ) && is_array( $placeholder_info['aliases'] ) ){ - + if ( isset( $placeholder_info['aliases'] ) && is_array( $placeholder_info['aliases'] ) ) { + $string = str_replace( $placeholder_info['aliases'], $replace_with, $string ); - + } // replace $string = str_replace( $main_placeholder_key, $replace_with, $string ); - } else { // not in index, replace requested placeholder: $string = str_replace( $this->make_placeholder_str( $placeholder_key ), $replace_with, $string ); } - - return $string; + return $string; } - /** * Enacts replacements on a string based on passed tooling/areas * Note: Using this method allows non-passed values to be emptied, - * e.g. if 'global' tooling method, and no 'unsub-line' value passed, + * e.g. if 'global' tooling method, and no 'unsub-line' value passed, * any mentions of '##UNSUB-LINE##' will be taken out of $string * * @param array|string tooling - tooling area, object type, or group of @@ -1642,15 +1599,13 @@ public function replace_single_placeholder( $placeholder_key = '', $replace_with * * @return string modified string */ - public function replace_placeholders( - + public function replace_placeholders( $tooling = array( 'global' ), $string = '', $replacements = array(), $replacement_objects = false, $retain_unset_placeholders = false, $keys_staying_unrendered = array() - ) { // retrieve replacements for this tooling @@ -1663,14 +1618,14 @@ public function replace_placeholders( // ##BIZ-STATE## -> biz-state $key = str_replace( '#', '', strtolower( $replace_string ) ); - if ( isset( $replacement_info['key'] ) && !empty( $replacement_info['key'] ) ) { + if ( isset( $replacement_info['key'] ) && ! empty( $replacement_info['key'] ) ) { $key = $replacement_info['key']; } // attempt to find value in $replacements - $replace_with = ''; + $replace_with = ''; if ( isset( $replacements[ $key ] ) ) { $replace_with = $replacements[ $key ]; @@ -1681,29 +1636,28 @@ public function replace_placeholders( // ... if $replacements[value] not already set (that overrides) // here $key will be 'contact-prefix' // .. which would map to $replacement_objects[ZBS_TYPE_CONTACT]['prefix'] - if ( empty( $replace_with ) ){ + if ( empty( $replace_with ) ) { // attempt to pluck relative value $potential_value = $this->pick_from_replacement_objects( $key, $replacement_objects ); - if ( !empty( $potential_value ) ) { + if ( ! empty( $potential_value ) ) { $replace_with = $potential_value; } - } // if $key is 'assigned-to-name', 'assigned-to-email', 'assigned-to-mob' - seek out an owner. // ... if $replacements[assigned-to-name] not already set (that overrides) - if ( empty( $replace_with ) && in_array( $key, array( 'assigned-to-name', 'assigned-to-email', 'assigned-to-username', 'assigned-to-mob' ) ) && is_array( $replacement_objects ) ){ + if ( empty( $replace_with ) && in_array( $key, array( 'assigned-to-name', 'assigned-to-email', 'assigned-to-username', 'assigned-to-mob' ) ) && is_array( $replacement_objects ) ) { $owner_value = ''; - $owner_info = $this->owner_from_replacement_objects( $replacement_objects ); + $owner_info = $this->owner_from_replacement_objects( $replacement_objects ); - if ( $owner_info ){ + if ( $owner_info ) { - switch ( $key ){ + switch ( $key ) { case 'assigned-to-name': $owner_value = $owner_info->display_name; @@ -1715,24 +1669,22 @@ public function replace_placeholders( $owner_value = $owner_info->user_email; break; case 'assigned-to-mob': - $owner_value = zeroBS_getWPUsersMobile($owner_info->ID); + $owner_value = zeroBS_getWPUsersMobile( $owner_info->ID ); break; } // got value? - if ( !empty( $owner_value ) ) { + if ( ! empty( $owner_value ) ) { $replace_with = $owner_value; } - } - } // replace (if not empty + retain_unset_placeholders) - if ( !$retain_unset_placeholders || ( $retain_unset_placeholders && !empty( $replace_with ) ) ){ + if ( ! $retain_unset_placeholders || ( $retain_unset_placeholders && ! empty( $replace_with ) ) ) { // here we hit a problem, we've been wild with our ### use, so now we // have a mixture of ## and ### references. @@ -1741,10 +1693,10 @@ public function replace_placeholders( // for now, replacing aliases first solves this. // aliases - if ( isset( $replacement_info['aliases'] ) && is_array( $replacement_info['aliases'] ) ){ - + if ( isset( $replacement_info['aliases'] ) && is_array( $replacement_info['aliases'] ) ) { + $string = str_replace( $replacement_info['aliases'], $replace_with, $string ); - + } // If this is a Quote date key and is not set (Quote accepted or last viewed), let's print out a message saying the quote isn't accepted or viewed. @@ -1772,23 +1724,18 @@ public function replace_placeholders( } } - } - } return $string; - } - - /** * Takes an array of replacement_objects and a target string * ... and returns a value if it can pick one from replacement_objects * ... e.g. target_string = 'contact-fname' - * ... = - * ... replacement_objects[ZBS_TYPE_CONTACT]['fname'] + * ... = + * ... replacement_objects[ZBS_TYPE_CONTACT]['fname'] * * @param string target string e.g. `contact-fname` * @param array|bool replacement objects, keyed to object type - (e.g. contact) Should be in the format array[ZBS_TYPE_CONTACT] = contact array @@ -1800,7 +1747,7 @@ private function pick_from_replacement_objects( $target_string = '', $replacemen global $zbs; // got string and replacement objects? - if ( !empty( $target_string ) && is_array( $replacement_objects ) && count( $replacement_objects ) > 0 ) { + if ( ! empty( $target_string ) && is_array( $replacement_objects ) && count( $replacement_objects ) > 0 ) { // retrieve object-type from $target_string (where possible) $target_exploded = explode( '-', $target_string, 2 ); @@ -1816,7 +1763,7 @@ private function pick_from_replacement_objects( $target_string = '', $replacemen array_shift( $target_exploded ); $field_name = strtolower( $target_exploded[0] ); - if ( isset( $replacement_objects[ $object_type_id ][ $field_name ] ) && !empty( $replacement_objects[ $object_type_id ][ $field_name ] ) ) { + if ( isset( $replacement_objects[ $object_type_id ][ $field_name ] ) && ! empty( $replacement_objects[ $object_type_id ][ $field_name ] ) ) { // successful find return $replacement_objects[ $object_type_id ][ $field_name ]; @@ -1837,7 +1784,6 @@ private function pick_from_replacement_objects( $target_string = '', $replacemen return $potential_uts_value; } } - } elseif ( preg_match( '/_date_str$/', $field_name ) ) { $potential_uts_field = str_replace( '_date_str', '', $field_name ); @@ -1850,60 +1796,47 @@ private function pick_from_replacement_objects( $target_string = '', $replacemen return $potential_uts_value; } } - } - } - } - } return false; - } - /** - * Takes an array of replacement_objects and returns WordPress user info + * Takes an array of replacement_objects and returns WordPress user info * for the first owner it finds in $replacement_objects * * @param array|bool replacement objects, keyed to object type - (e.g. contact) Should be in the format array[ZBS_TYPE_CONTACT] = contact array * * @return string WordPress user info (get_userdata) */ - private function owner_from_replacement_objects( $replacement_objects = array() ){ + private function owner_from_replacement_objects( $replacement_objects = array() ) { // got string and replacement objects? - if ( is_array( $replacement_objects ) && count( $replacement_objects ) > 0 ) { + if ( is_array( $replacement_objects ) && count( $replacement_objects ) > 0 ) { - foreach ( $replacement_objects as $replacement_obj_type => $replacement_object){ + foreach ( $replacement_objects as $replacement_obj_type => $replacement_object ) { // is `owner` set? - if ( isset( $replacement_object['owner'] ) && !empty( $replacement_object['owner'] ) ){ + if ( isset( $replacement_object['owner'] ) && ! empty( $replacement_object['owner'] ) ) { - // one of the passed replacement objects has an owner... first passed first served - $user_info = get_userdata($replacement_object['owner']); + // one of the passed replacement objects has an owner... first passed first served + $user_info = get_userdata( $replacement_object['owner'] ); - if ( $user_info !== false){ + if ( $user_info !== false ) { return $user_info; } - } - } - } return false; - } - - - /** * Takes a key (e.g. msg-content) and returns in valid placeholder * format. (e.g. ##MSG-CONTENT##) @@ -1912,13 +1845,10 @@ private function owner_from_replacement_objects( $replacement_objects = array() * * @return string valid placeholder string */ - public function make_placeholder_str( $placeholder_key = '' ){ + public function make_placeholder_str( $placeholder_key = '' ) { return '##' . str_replace( '_', '-', trim( strtoupper( $placeholder_key ) ) ) . '##'; - } - - /** * Draws WYSIWYG Typeahead (Bloodhound JS) @@ -1930,12 +1860,12 @@ public function make_placeholder_str( $placeholder_key = '' ){ * * @return string valid placeholder string */ - public function placeholder_selector( $id = '', $insert_target_id = '', $tooling = array('global'), $return = false, $extra_classes = '' ){ + public function placeholder_selector( $id = '', $insert_target_id = '', $tooling = array( 'global' ), $return = false, $extra_classes = '' ) { $placeholder_list = array(); // Simpler '; + $html = '
'; + $html .= '
'; + } + $html .= ''; - if ( !$return ){ + if ( ! $return ) { echo $html; } return $html; - } - /** * Collates and tidies the full output of placeholders into a simpler array (for placeholder selector typeahead primarily) - * + * * @param array placeholders - array of placeholders, probably from $this->get_placeholders or $this->get_placeholders_for_tooling (Note this requires non-categorised array) * * @return array placeholders - simplified array */ - public function simplify_placeholders( $placeholders = array() ){ + public function simplify_placeholders( $placeholders = array() ) { $return = array(); // cycle through and simplify - foreach ( $placeholders as $key => $info ){ + foreach ( $placeholders as $key => $info ) { $placeholder = $info; @@ -2026,7 +1949,7 @@ public function simplify_placeholders( $placeholders = array() ){ unset( $placeholder['available_in'], $placeholder['associated_type'] ); // if return_str not set and key is, add it - if ( !isset( $placeholder['replace_str'] ) ){ + if ( ! isset( $placeholder['replace_str'] ) ) { $placeholder['replace_str'] = $key; @@ -2034,14 +1957,11 @@ public function simplify_placeholders( $placeholders = array() ){ $return[] = $placeholder; - } return $return; - } - /** * Collates and tidies the full output of placeholders into a simpler array (designed for wysiwyg select insert - e.g. quotebuilder) * @@ -2049,23 +1969,23 @@ public function simplify_placeholders( $placeholders = array() ){ * * @return array placeholders - simplified array (array[{text:desc,value:placeholder}]) */ - public function simplify_placeholders_for_wysiwyg( $placeholders = array() ){ + public function simplify_placeholders_for_wysiwyg( $placeholders = array() ) { $return = array(); // cycle through and simplify - foreach ( $placeholders as $placeholder_key => $placeholder_info ){ + foreach ( $placeholders as $placeholder_key => $placeholder_info ) { // label - $placeholder_label = ( isset( $placeholder_info['description'] ) && !empty( $placeholder_info['description'] ) ) ? $placeholder_info['description'] . ' (' . $placeholder_key .')' : $placeholder_key; - - - $return[] = array( 'text' => $placeholder_label, 'value' => $placeholder_key); + $placeholder_label = ( isset( $placeholder_info['description'] ) && ! empty( $placeholder_info['description'] ) ) ? $placeholder_info['description'] . ' (' . $placeholder_key . ')' : $placeholder_key; + $return[] = array( + 'text' => $placeholder_label, + 'value' => $placeholder_key, + ); } return $return; - } } diff --git a/projects/plugins/crm/includes/jpcrm-templating.php b/projects/plugins/crm/includes/jpcrm-templating.php index 60efdc9dd94c..aae1d5d40154 100644 --- a/projects/plugins/crm/includes/jpcrm-templating.php +++ b/projects/plugins/crm/includes/jpcrm-templating.php @@ -1,5 +1,5 @@ -template_path . '/' . $template_file, - $template_file - ) ); + $template_file_path = locate_template( + array( + $zbs->template_path . '/' . $template_file, + $template_file, + ) + ); - - // check any other externally added locations + // check any other externally added locations // default to our core template if no theme or external variant - if ( !$template_file_path ){ + if ( ! $template_file_path ) { // see if we have any other locations // note this'll effectively 'pick' the first added & viable in this situation. $extra_template_locations = apply_filters( 'jpcrm_template_locations', array() ); - if ( is_array( $extra_template_locations ) ){ + if ( is_array( $extra_template_locations ) ) { - foreach ( $extra_template_locations as $location ){ + foreach ( $extra_template_locations as $location ) { - if ( file_exists( $location[ 'path' ] . $template_file ) ){ + if ( file_exists( $location['path'] . $template_file ) ) { // use this template - $template_file_path = $location[ 'path' ] . $template_file; + $template_file_path = $location['path'] . $template_file; break; } - - } - } // no theme template @@ -63,45 +60,41 @@ function jpcrm_template_file_path( $template_file = '' ) { $template_file_path = ZEROBSCRM_PATH . 'templates/' . $template_file; } - } - // do we have a valid template? - if ( !empty( $template_file_path ) && file_exists( $template_file_path ) ){ + if ( ! empty( $template_file_path ) && file_exists( $template_file_path ) ) { return $template_file_path; } - } return false; - } /** * Retrieve Template file - * + * * This checks existence in /wp-content/theme/{active_theme}/jetpack-crm/* * ... and if doesn't exist, falls back to /wp-content/plugin/{this_plugin}/templates/* * * @param string template_file - the file path _after_ the /templates/ directory * @param bool load - if true will include - * - * @return string {contents_of_template_file} + * + * @return string {contents_of_template_file} */ function jpcrm_retrieve_template( $template_file = '', $load = true ) { $template_contents = ''; - if ( !empty( $template_file ) ){ + if ( ! empty( $template_file ) ) { // retrieve path $template_file_path = jpcrm_template_file_path( $template_file ); // do we have a valid template? - if ( !empty( $template_file_path ) && file_exists( $template_file_path ) ){ + if ( ! empty( $template_file_path ) && file_exists( $template_file_path ) ) { // Prevent file traversal attacks. $allowed_template_paths = jpcrm_get_allowed_template_paths(); @@ -110,48 +103,42 @@ function jpcrm_retrieve_template( $template_file = '', $load = true ) { } // load or return contents - if ( $load ){ + if ( $load ) { // load the file directly (no support for require_once here, expand via params if needed) include $template_file_path; } else { - + // retrieve contents - if (function_exists('file_get_contents')){ + if ( function_exists( 'file_get_contents' ) ) { - try { + try { - $template_contents = file_get_contents( $template_file_path ); + $template_contents = file_get_contents( $template_file_path ); return $template_contents; + } catch ( Exception $e ) { - } catch (Exception $e){ - - // Nada + // Nada // basic dialog _doing_it_wrong( __FUNCTION__, sprintf( '%s could not be retrieved.', esc_html( $template_file_path ) ), '4.5.0' ); - + // add admin notification - if ( zeroBSCRM_isZBSAdminOrAdmin() ){ - + if ( zeroBSCRM_isZBSAdminOrAdmin() ) { + jpcrm_template_missing_notification( $template_file ); } - - } - - } - - + } + } } - } else { // if current user is an admin, let's return a useful debug string - if ( zeroBSCRM_isZBSAdminOrAdmin() ){ - - // add admin notification + if ( zeroBSCRM_isZBSAdminOrAdmin() ) { + + // add admin notification jpcrm_template_missing_notification( $template_file ); // return explainer string (note this'll get rolled into PDF/page output) @@ -163,15 +150,11 @@ function jpcrm_retrieve_template( $template_file = '', $load = true ) { // _doing_it_wrong( __FUNCTION__, sprintf( '%s does not exist.', $template_file ) ); } - } - } - // no dice return ''; - } /** @@ -201,7 +184,7 @@ function jpcrm_retrieve_template_variants( $original_template_path = '' ) { $variants = array(); - if ( !empty( $original_template_path ) ){ + if ( ! empty( $original_template_path ) ) { // get extension (e.g. html) $file_extension = pathinfo( $original_template_path, PATHINFO_EXTENSION ); @@ -216,7 +199,9 @@ function jpcrm_retrieve_template_variants( $original_template_path = '' ) { // to provide some form of protection here, we only allow zbs admins to do this // (as we're iterating through directories) - if ( !zeroBSCRM_isZBSAdminOrAdmin() ) return false; + if ( ! zeroBSCRM_isZBSAdminOrAdmin() ) { + return false; + } // Seeks out template files matching a pattern (in wp theme directories, and our core template directory) // Adapted from locate_template: https://core.trac.wordpress.org/browser/tags/5.8/src/wp-includes/template.php#L697 @@ -225,15 +210,15 @@ function jpcrm_retrieve_template_variants( $original_template_path = '' ) { 'name' => __( 'Theme directory', 'zero-bs-crm' ), 'path' => get_stylesheet_directory() . '/' . $zbs->template_path . '/', ), - array( + array( 'name' => __( 'Template Path directory', 'zero-bs-crm' ), 'path' => get_template_directory() . '/' . $zbs->template_path . '/', ), - array( - 'name' => __( 'Theme Compat directory', 'zero-bs-crm' ), + array( + 'name' => __( 'Theme Compat directory', 'zero-bs-crm' ), 'path' => ABSPATH . WPINC . '/theme-compat/' . $zbs->template_path . '/', ), - array( + array( 'name' => __( 'Core Plugin', 'zero-bs-crm' ), 'path' => ZEROBSCRM_PATH . 'templates/', ), @@ -247,13 +232,13 @@ function jpcrm_retrieve_template_variants( $original_template_path = '' ) { // cycle through locations and seek out templates if ( is_array( $template_locations ) ) { - foreach ( $template_locations as $directory ){ - + foreach ( $template_locations as $directory ) { + // locate matching files - $template_files = glob( $directory['path'] . $pre_extension_path . '*.' . $file_extension); + $template_files = glob( $directory['path'] . $pre_extension_path . '*.' . $file_extension ); // determine viable - if ( is_array( $template_files ) ){ + if ( is_array( $template_files ) ) { foreach ( $template_files as $file_path ) { @@ -262,28 +247,21 @@ function jpcrm_retrieve_template_variants( $original_template_path = '' ) { $variants[ $path ] = array( 'full_path' => $file_path, - 'filename' => basename( $file_path ), - 'origin' => $directory['name'], - 'name' => '' // tbc + 'filename' => basename( $file_path ), + 'origin' => $directory['name'], + 'name' => '', // tbc ); } - } - } - } - } // return passed through filter so the likes of client portal pro could append return apply_filters( 'jpcrm_template_variants', $variants, $original_template_path ); - } - - /** * Adds an admin notice for missing template * @@ -293,7 +271,7 @@ function jpcrm_retrieve_template_variants( $original_template_path = '' ) { */ function jpcrm_template_missing_notification( $template_file = '' ) { - if ( !empty( $template_file ) ){ + if ( ! empty( $template_file ) ) { global $zbs; @@ -317,17 +295,16 @@ function jpcrm_template_missing_notification( $template_file = '' ) { } return false; - - } -/* WH Notes: +/* +WH Notes: There was all this note-age from old vers: - Customer Meta Translation - 2.90 + Customer Meta Translation - 2.90 #}PUT THE EMAIL THROUGH THE FILTERS (FOR THE #FNAME# NEW CUSTOMER TAGS do prepare_email_{trigger}_template #} WH: Let's do this as filters :) - + ... but I think these funcs needed a bit of a clean up ... should be backward compatible, and safe to stick to using the filter: zeroBSCRM_replace_customer_placeholders ... MC2.0 uses this indirectly through 'zerobscrm_mailcamp_merge' and 'zerobscrm_mailcamp_merge_text' @@ -336,15 +313,15 @@ function jpcrm_template_missing_notification( $template_file = '' ) { ... v3.0 I've made them DAL3 safe, not fully refactored as approaching deadline */ // Note: this function is deprecated from ~4.3.0, please use $zbs->get_templating()->replace_placeholders() -function zeroBSCRM_replace_customer_placeholders($html = '', $cID = -1, $contactObj = false){ +function zeroBSCRM_replace_customer_placeholders( $html = '', $cID = -1, $contactObj = false ) { - if ($cID > 0 && $html != ''){ + if ( $cID > 0 && $html != '' ) { global $zbs; - if (is_array($contactObj) && isset($contactObj['id'])) + if ( is_array( $contactObj ) && isset( $contactObj['id'] ) ) { $contact = $contactObj; - else { + } else { $contact = $zbs->DAL->contacts->getContact( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase $cID, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase array( @@ -365,24 +342,23 @@ function zeroBSCRM_replace_customer_placeholders($html = '', $cID = -1, $contact // replace all placeholders :) $newHTML = $html; - foreach ($contact as $k => $v){ - $newHTML = str_replace('##CONTACT-'.strtoupper($k) . '##' ,$v, $newHTML); + foreach ( $contact as $k => $v ) { + $newHTML = str_replace( '##CONTACT-' . strtoupper( $k ) . '##', $v, $newHTML ); } $html = $newHTML; } - return $html; - + return $html; } -add_filter( 'zerobscrm_quote_html_generate','zeroBSCRM_replace_customer_placeholders', 20, 2); +add_filter( 'zerobscrm_quote_html_generate', 'zeroBSCRM_replace_customer_placeholders', 20, 2 ); // as above, but replaces with 'demo data' -function zeroBSCRM_replace_customer_placeholders_demo( $html = '' ){ - - if ( !empty( $html ) ){ - +function zeroBSCRM_replace_customer_placeholders_demo( $html = '' ) { + + if ( ! empty( $html ) ) { + global $zbs; // load templater @@ -391,17 +367,17 @@ function zeroBSCRM_replace_customer_placeholders_demo( $html = '' ){ // assigned-to-* $replacements = array( - 'assigned-to-name' => __( 'Demo Contact Owner', 'zero-bs-crm' ), - 'assigned-to-email' => 'demo.contact.owner@example.com', + 'assigned-to-name' => __( 'Demo Contact Owner', 'zero-bs-crm' ), + 'assigned-to-email' => 'demo.contact.owner@example.com', 'assigned-to-username' => 'demo.contact.owner.username', - 'assigned-to-mob' => '999 999 999', + 'assigned-to-mob' => '999 999 999', ); // return the example, with demo contact fields and assignments replaced - return $placeholder_templating->replace_placeholders( array( 'global', 'contact' ), $html, $replacements, array( ZBS_TYPE_CONTACT => zeroBS_getDemoCustomer() ), true ); + return $placeholder_templating->replace_placeholders( array( 'global', 'contact' ), $html, $replacements, array( ZBS_TYPE_CONTACT => zeroBS_getDemoCustomer() ), true ); } - return $html; + return $html; } diff --git a/projects/plugins/crm/includes/jpcrm-usage-tracking.php b/projects/plugins/crm/includes/jpcrm-usage-tracking.php index 0d2664e17b92..400472eebafa 100644 --- a/projects/plugins/crm/includes/jpcrm-usage-tracking.php +++ b/projects/plugins/crm/includes/jpcrm-usage-tracking.php @@ -1,406 +1,393 @@ init_hooks(); - - } - - public function init_hooks(){ - - #} Usage tracking (pageviews) sent via AJAX - add_action('admin_footer', array($this, 'tracking_footer')); - add_action('wp_ajax_jpcrm_send_page_view', array($this, 'send_page_view')); - - } - - /** - * AJAX function to send the pageview - */ - public function send_page_view(){ - - global $zbs; - - $res = array(); - - // check nonce - check_ajax_referer( 'jpcrm_usage_tracking_nonce', 'security' ); - - // retrieve page_name - $page_name = sanitize_text_field($_POST['page_name']); - - // pool data - $data = array( - 'action' => 'jpcrm_track_usage', - 'event_name' => $page_name, - 'event_type' => 'page_view', - 'site_url' => home_url() - ); - - // call - $response = wp_remote_post( $zbs->urls['usage'], array( - 'method' => 'POST', - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => '1.0', - 'blocking' => true, - 'headers' => array(), - 'body' => $data, - 'cookies' => array() - ) - ); - - $res['pageview'] = 'sent'; - - // send summary snapshot based on a transient - if(!get_transient('jpcrm_crm_snapshot')){ - - $this->send_snapshot(); - $res['snapshot'] = 'sent'; - set_transient( 'jpcrm_crm_snapshot', true, DAY_IN_SECONDS ); - - } - - wp_send_json($res); - - } - - /** - * send summary snapshot - */ - public function send_snapshot(){ - - global $zbs, $wp_version; - - // build data - $contacts_count = $zbs->DAL->contacts->getFullCount(); - $contacts_woo_count = $zbs->DAL->contacts->getContacts( array( - - 'externalSource' => 'woo', - 'count' => true - - )); - $contacts_with_extsource = $zbs->DAL->contacts->getTotalExtSourceCount(); - $companies_count = $zbs->DAL->companies->getFullCount(); - $transactions_count = $zbs->DAL->transactions->getFullCount(); - $quotes_count = $zbs->DAL->quotes->getFullCount(); - $invoices_count = $zbs->DAL->invoices->getFullCount(); - $forms_count = $zbs->DAL->forms->getFullCount(); - $tasks_count = $zbs->DAL->events->getFullCount(); - $crm_users = $this->get_teammates_count( true ); - $extensions_count = zeroBSCRM_extensionsInstalledCount(); - $modules_count = jpcrm_core_modules_installed_count(); - $wp_version = $wp_version; +class jpcrm_usage_tracking { + + protected $setting_key = 'teammember_usage'; + + public function __construct() { + + $this->init_hooks(); + } + + public function init_hooks() { + + #} Usage tracking (pageviews) sent via AJAX + add_action( 'admin_footer', array( $this, 'tracking_footer' ) ); + add_action( 'wp_ajax_jpcrm_send_page_view', array( $this, 'send_page_view' ) ); + } + + /** + * AJAX function to send the pageview + */ + public function send_page_view() { + + global $zbs; + + $res = array(); + + // check nonce + check_ajax_referer( 'jpcrm_usage_tracking_nonce', 'security' ); + + // retrieve page_name + $page_name = sanitize_text_field( $_POST['page_name'] ); + + // pool data + $data = array( + 'action' => 'jpcrm_track_usage', + 'event_name' => $page_name, + 'event_type' => 'page_view', + 'site_url' => home_url(), + ); + + // call + $response = wp_remote_post( + $zbs->urls['usage'], + array( + 'method' => 'POST', + 'timeout' => 45, + 'redirection' => 5, + 'httpversion' => '1.0', + 'blocking' => true, + 'headers' => array(), + 'body' => $data, + 'cookies' => array(), + ) + ); + + $res['pageview'] = 'sent'; + + // send summary snapshot based on a transient + if ( ! get_transient( 'jpcrm_crm_snapshot' ) ) { + + $this->send_snapshot(); + $res['snapshot'] = 'sent'; + set_transient( 'jpcrm_crm_snapshot', true, DAY_IN_SECONDS ); + + } + + wp_send_json( $res ); + } + + /** + * send summary snapshot + */ + public function send_snapshot() { + + global $zbs, $wp_version; + + // build data + $contacts_count = $zbs->DAL->contacts->getFullCount(); + $contacts_woo_count = $zbs->DAL->contacts->getContacts( + array( + + 'externalSource' => 'woo', + 'count' => true, + + ) + ); + $contacts_with_extsource = $zbs->DAL->contacts->getTotalExtSourceCount(); + $companies_count = $zbs->DAL->companies->getFullCount(); + $transactions_count = $zbs->DAL->transactions->getFullCount(); + $quotes_count = $zbs->DAL->quotes->getFullCount(); + $invoices_count = $zbs->DAL->invoices->getFullCount(); + $forms_count = $zbs->DAL->forms->getFullCount(); + $tasks_count = $zbs->DAL->events->getFullCount(); + $crm_users = $this->get_teammates_count( true ); + $extensions_count = zeroBSCRM_extensionsInstalledCount(); + $modules_count = jpcrm_core_modules_installed_count(); + $wp_version = $wp_version; $crm_version = $zbs::VERSION; - $dal_version = $zbs->dal_version; - $php_version = PHP_VERSION; - $mysql_version = zeroBSCRM_database_getVersion(); - - $data = array( - 'action' => 'jpcrm_track_stats', - 'site_url' => home_url(), - 'contacts_count' => $contacts_count, - 'contacts_woo_count' => $contacts_woo_count, - 'contacts_with_extsource' => $contacts_with_extsource, - 'companies_count' => $companies_count, - 'transactions_count' => $transactions_count, - 'quotes_count' => $quotes_count, - 'invoices_count' => $invoices_count, - 'forms_count' => $forms_count, - 'events_count' => $tasks_count, - 'users_count' => $crm_users, - 'extensions_count' => $extensions_count, - 'modules_count' => $modules_count, - 'wp_version' => $wp_version, - 'crm_version' => $crm_version, - 'dal_version' => $dal_version, - 'php_version' => $php_version, - 'mysql_version' => $mysql_version, - ); - - - // call - return wp_remote_post( $zbs->urls['usage'], array( - 'method' => 'POST', - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => '1.0', - 'blocking' => true, - 'headers' => array(), - 'body' => $data, - 'cookies' => array() - ) - ); - - } - - /** - * Package admin page as string which can be passed to usage tracking API - */ - public function get_jpcrm_admin_page(){ - - // retrieve uri - $uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; - $uri = preg_replace( '|^.*/wp-admin/|i', '', $uri ); - - // if somehow failed, return - if ( ! $uri ) { - return ''; - } - - // hard remove any unwanted get parameters here - $uri = remove_query_arg( array( '_wpnonce' ), admin_url( $uri ) ); - - // get _GET Parameters - $parameters = jpcrm_url_get_params( $uri ); - - // cycle through some key parameters and tokenise for anonymity / cleanliness - if ( is_array( $parameters ) ) { - - $return_string = ''; - - // required: page - if ( isset( $parameters['page'] ) && !empty ( $parameters['page'] ) ){ - - $return_string = $parameters['page']; - - } else { - - // missing $page, skip - return ''; - - } - - // Overrides: + $dal_version = $zbs->dal_version; + $php_version = PHP_VERSION; + $mysql_version = zeroBSCRM_database_getVersion(); + + $data = array( + 'action' => 'jpcrm_track_stats', + 'site_url' => home_url(), + 'contacts_count' => $contacts_count, + 'contacts_woo_count' => $contacts_woo_count, + 'contacts_with_extsource' => $contacts_with_extsource, + 'companies_count' => $companies_count, + 'transactions_count' => $transactions_count, + 'quotes_count' => $quotes_count, + 'invoices_count' => $invoices_count, + 'forms_count' => $forms_count, + 'events_count' => $tasks_count, + 'users_count' => $crm_users, + 'extensions_count' => $extensions_count, + 'modules_count' => $modules_count, + 'wp_version' => $wp_version, + 'crm_version' => $crm_version, + 'dal_version' => $dal_version, + 'php_version' => $php_version, + 'mysql_version' => $mysql_version, + ); - // action: by default it's add, unless zbsid is set, then it's edit, make so: - if ( isset( $parameters['action'] ) && !empty( $parameters['action'] ) ){ + // call + return wp_remote_post( + $zbs->urls['usage'], + array( + 'method' => 'POST', + 'timeout' => 45, + 'redirection' => 5, + 'httpversion' => '1.0', + 'blocking' => true, + 'headers' => array(), + 'body' => $data, + 'cookies' => array(), + ) + ); + } - // if action is set and no zbsid is present, it's an add - if ( - $parameters['action'] == 'edit' && ( - !isset( $parameters['zbsid'] ) || empty( $parameters['zbsid'] ) - ) ){ + /** + * Package admin page as string which can be passed to usage tracking API + */ + public function get_jpcrm_admin_page() { - $parameters['action'] = 'add'; - } + // retrieve uri + $uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; + $uri = preg_replace( '|^.*/wp-admin/|i', '', $uri ); - // note if there's an action present and zbsid, we can go ahead and remove zbsid from the return :) - if ( isset( $parameters['zbsid'] ) ){ - - unset( $parameters['zbsid'] ); - - } + // if somehow failed, return + if ( ! $uri ) { + return ''; + } + // hard remove any unwanted get parameters here + $uri = remove_query_arg( array( '_wpnonce' ), admin_url( $uri ) ); - } + // get _GET Parameters + $parameters = jpcrm_url_get_params( $uri ); - // generic out any non-helpful data - $parameters_to_blank = array( 'zbsid', 'zbsprefillcust', 'zbsprefill', 'zbs_tag', 'quickfilters', 'sort', 'zbsowner', 'zbs_template_id' ); + // cycle through some key parameters and tokenise for anonymity / cleanliness + if ( is_array( $parameters ) ) { - foreach ( $parameters_to_blank as $parameter_key ){ + $return_string = ''; - if ( isset( $parameters[ $parameter_key ] ) ){ + // required: page + if ( isset( $parameters['page'] ) && ! empty( $parameters['page'] ) ) { - // set generic value - $parameters[ $parameter_key ] = 'present'; + $return_string = $parameters['page']; - } + } else { - } + // missing $page, skip + return ''; - // finally rebuild into a useful string - foreach ( $parameters as $parameter_key => $parameter_value){ + } - // skip page as is always added above - if ( $parameter_key == 'page' ){ + // Overrides: - continue; + // action: by default it's add, unless zbsid is set, then it's edit, make so: + if ( isset( $parameters['action'] ) && ! empty( $parameters['action'] ) ) { - } + // if action is set and no zbsid is present, it's an add + if ( $parameters['action'] == 'edit' && ( + ! isset( $parameters['zbsid'] ) || empty( $parameters['zbsid'] ) + ) ) { - if ( !empty( $return_string ) ){ + $parameters['action'] = 'add'; + } - $return_string .= '|'; + // note if there's an action present and zbsid, we can go ahead and remove zbsid from the return :) + if ( isset( $parameters['zbsid'] ) ) { - } + unset( $parameters['zbsid'] ); - // here we check if $parameter_value might be an email - // ... designed as future-proofing and to catch any potential leaks of user data to our system - if ( zeroBSCRM_validateEmail( $parameter_value ) ) $parameter_value = '{email}'; + } + } - // append return string - $return_string .= $parameter_key . ':' . $parameter_value; + // generic out any non-helpful data + $parameters_to_blank = array( 'zbsid', 'zbsprefillcust', 'zbsprefill', 'zbs_tag', 'quickfilters', 'sort', 'zbsowner', 'zbs_template_id' ); - } + foreach ( $parameters_to_blank as $parameter_key ) { - return $return_string; + if ( isset( $parameters[ $parameter_key ] ) ) { - } + // set generic value + $parameters[ $parameter_key ] = 'present'; + } + } - // fallback: retrieve page via explode - $split = explode("?page=",$uri); - $page = $split[0]; - if(count($split) == 2){ - $page = $split[1]; - } + // finally rebuild into a useful string + foreach ( $parameters as $parameter_key => $parameter_value ) { - // returns everything after the ?page= part of the URL - return $page; + // skip page as is always added above + if ( $parameter_key == 'page' ) { - } + continue; + } + if ( ! empty( $return_string ) ) { - /** - * JS to track usage - */ - public function tracking_footer(){ + $return_string .= '|'; - global $zbs; + } - if ( zeroBSCRM_isAdminPage() ){ - - // retrieve page info - $page = $this->get_jpcrm_admin_page(); + // here we check if $parameter_value might be an email + // ... designed as future-proofing and to catch any potential leaks of user data to our system + if ( zeroBSCRM_validateEmail( $parameter_value ) ) { + $parameter_value = '{email}'; + } - if ( !empty( $page ) ){ + // append return string + $return_string .= $parameter_key . ':' . $parameter_value; - $this->track_specific_pageview( $page ); + } - } + return $return_string; - } + } - } + // fallback: retrieve page via explode + $split = explode( '?page=', $uri ); + $page = $split[0]; + if ( count( $split ) == 2 ) { + $page = $split[1]; + } + // returns everything after the ?page= part of the URL + return $page; + } - /** - * JS to track usage for a specific key - * is used by `tracking_footer()` and can be used inline throughout - * core to track extra view events - */ - public function track_specific_pageview( $page_key = '' ){ + /** + * JS to track usage + */ + public function tracking_footer() { - global $zbs; + global $zbs; - if ( zeroBSCRM_isAdminPage() ){ + if ( zeroBSCRM_isAdminPage() ) { - // Where usage tracking enabled, clock that this user is a CRM team member - // noting that this never sends team-member data out of the install, only the count - $this->track_crm_teammember_usage(); + // retrieve page info + $page = $this->get_jpcrm_admin_page(); - if ( !empty( $page_key ) ){ + if ( ! empty( $page ) ) { - ?> - - track_specific_pageview( $page ); - } + } + } + } + /** + * JS to track usage for a specific key + * is used by `tracking_footer()` and can be used inline throughout + * core to track extra view events + */ + public function track_specific_pageview( $page_key = '' ) { - } + global $zbs; - } + if ( zeroBSCRM_isAdminPage() ) { + // Where usage tracking enabled, clock that this user is a CRM team member + // noting that this never sends team-member data out of the install, only the count + $this->track_crm_teammember_usage(); - /** - * Adds user id to an option of "WP users who use the CRM" which is totalled for usage statistics - * (No specific user usage data is ever sent) - */ - private function track_crm_teammember_usage(){ + if ( ! empty( $page_key ) ) { - global $zbs; + ?> + + settings->get( $this->setting_key ); + } + } + } - // catch first call - if ( !is_array( $existing_teammembers ) ){ - $existing_teammembers = array(); - } + /** + * Adds user id to an option of "WP users who use the CRM" which is totalled for usage statistics + * (No specific user usage data is ever sent) + */ + private function track_crm_teammember_usage() { - $current_user_id = get_current_user_id(); + global $zbs; - // append - if ( isset( $existing_teammembers[ $current_user_id ] ) ){ + // retrieve existing array + $existing_teammembers = $zbs->settings->get( $this->setting_key ); - // increment - $existing_teammembers[ $current_user_id ]['count']++; + // catch first call + if ( ! is_array( $existing_teammembers ) ) { + $existing_teammembers = array(); + } - // update - $existing_teammembers[ $current_user_id ]['last_seen'] = time(); + $current_user_id = get_current_user_id(); - } else { + // append + if ( isset( $existing_teammembers[ $current_user_id ] ) ) { - // add - $existing_teammembers[ $current_user_id ] = array( 'count' => 1, 'last_seen' => time() ); + // increment + ++$existing_teammembers[ $current_user_id ]['count']; - } + // update + $existing_teammembers[ $current_user_id ]['last_seen'] = time(); - // update setting - $zbs->settings->update( $this->setting_key, $existing_teammembers ); + } else { - } + // add + $existing_teammembers[ $current_user_id ] = array( + 'count' => 1, + 'last_seen' => time(), + ); + } - /** - * Retrieves a count of teammates who have accessed a crm page (optionally checking wp user status) - * - * @param $check_is_current_wp_user - bool; if true check that the user_id is a current wp user - */ - public function get_teammates_count( $check_is_current_wp_crm_user = false ){ + // update setting + $zbs->settings->update( $this->setting_key, $existing_teammembers ); + } - global $zbs; + /** + * Retrieves a count of teammates who have accessed a crm page (optionally checking wp user status) + * + * @param $check_is_current_wp_user - bool; if true check that the user_id is a current wp user + */ + public function get_teammates_count( $check_is_current_wp_crm_user = false ) { - // retrieve teammembers - $seen_teammembers = $zbs->settings->get( $this->setting_key ); + global $zbs; - // catch first call - if ( !is_array( $seen_teammembers ) ){ - return 0; - } + // retrieve teammembers + $seen_teammembers = $zbs->settings->get( $this->setting_key ); - // if validating current status, do that, else return count - if ( $check_is_current_wp_crm_user ){ + // catch first call + if ( ! is_array( $seen_teammembers ) ) { + return 0; + } - // filter user_ids who are current wp_users - $current_wp_teammembers = array_filter( array_keys( $seen_teammembers ), 'get_userdata' ); + // if validating current status, do that, else return count + if ( $check_is_current_wp_crm_user ) { - // filter user_ids who do not have a CRM backend role (and are not admins) - // e.g. CRM admins who are now Subscribers - $current_wp_teammembers = array_filter( $current_wp_teammembers, 'zeroBSCRM_permsIsZBSUserOrAdmin' ); + // filter user_ids who are current wp_users + $current_wp_teammembers = array_filter( array_keys( $seen_teammembers ), 'get_userdata' ); - return count( $current_wp_teammembers ); + // filter user_ids who do not have a CRM backend role (and are not admins) + // e.g. CRM admins who are now Subscribers + $current_wp_teammembers = array_filter( $current_wp_teammembers, 'zeroBSCRM_permsIsZBSUserOrAdmin' ); - } else { + return count( $current_wp_teammembers ); - return count( $seen_teammembers ); + } else { - } + return count( $seen_teammembers ); - } + } + } } diff --git a/projects/plugins/crm/includes/wh.config.lib.php b/projects/plugins/crm/includes/wh.config.lib.php index dfb3cf6baa35..3c4b4534972d 100644 --- a/projects/plugins/crm/includes/wh.config.lib.php +++ b/projects/plugins/crm/includes/wh.config.lib.php @@ -1,557 +1,601 @@ -settingsKey = $config['conf_key']; - if (isset($config['conf_ver'])) $this->settingsVer = $config['conf_ver']; - if (isset($config['conf_defaults'])) $this->settingsDefault = $config['conf_defaults']; - if (isset($config['conf_plugin'])) $this->settingsPlugin = $config['conf_plugin']; - if (isset($config['conf_pluginver'])) $this->settingsPluginVer = $config['conf_pluginver']; - if (isset($config['conf_plugindbver'])) $this->settingsPluginDBVer = $config['conf_plugindbver']; - if (isset($config['conf_dmzkey'])) $this->settingsDMZKey = $config['conf_dmzkey']; - if (isset($config['conf_protected'])) $this->settingsProtected = $config['conf_protected']; - - } else exit('WHConfigLib initiated incorrectly.'); - - #} define dmz settings key - #} Set by passed config now $this->settingsDMZKey = $this->settingsKey . '_dmzregister'; - - #} Load direct - $this->loadFromDB(); $this->loadDMZFromDB(); - - #} Fill any missing vars - $this->validateAndUpdate(); - - #} If empty it's first run so init from defaults - if (empty($this->settings)) $this->initCreate(); - +class WHWPConfigLib { + + #} Main settings storage + private $settings; + private $settingsKey = false; + private $settingsVer = false; + private $settingsDefault = false; + private $settingsPlugin = false; + private $settingsPluginVer = false; + private $settingsPluginDBVer = false; + + #} DMZ Settings + private $settingsDMZRegister; + private $settingsDMZKey = false; + private $settingsDMZ; + + #} :) + private $whlibVer = '2.0'; + + #} added "protected" list of setting keys that don't get reset when resetting to default + private $settingsProtected = false; + + #} Constructor + function __construct( $config = array() ) { + + #} localise any passed config + if ( is_array( $config ) ) { + + if ( isset( $config['conf_key'] ) ) { + $this->settingsKey = $config['conf_key']; + } + if ( isset( $config['conf_ver'] ) ) { + $this->settingsVer = $config['conf_ver']; + } + if ( isset( $config['conf_defaults'] ) ) { + $this->settingsDefault = $config['conf_defaults']; + } + if ( isset( $config['conf_plugin'] ) ) { + $this->settingsPlugin = $config['conf_plugin']; + } + if ( isset( $config['conf_pluginver'] ) ) { + $this->settingsPluginVer = $config['conf_pluginver']; + } + if ( isset( $config['conf_plugindbver'] ) ) { + $this->settingsPluginDBVer = $config['conf_plugindbver']; + } + if ( isset( $config['conf_dmzkey'] ) ) { + $this->settingsDMZKey = $config['conf_dmzkey']; + } + if ( isset( $config['conf_protected'] ) ) { + $this->settingsProtected = $config['conf_protected']; + } + } else { + exit( 'WHConfigLib initiated incorrectly.' ); } - - #} Checks through defaults + existing and adds defaults where unset - function validateAndUpdate(){ - - foreach ($this->settingsDefault as $key => $val){ - if (!isset($this->settings[$key])) { - $this->update($key,$val); - } - } + #} define dmz settings key + #} Set by passed config now $this->settingsDMZKey = $this->settingsKey . '_dmzregister'; + + #} Load direct + $this->loadFromDB(); + $this->loadDMZFromDB(); + + #} Fill any missing vars + $this->validateAndUpdate(); + + #} If empty it's first run so init from defaults + if ( empty( $this->settings ) ) { + $this->initCreate(); } - - #} Initial Create - function initCreate(){ - - #} If properly initialised! - if ($settingsKey !== false && $settingsVer !== false && $settingsDefault !== false && $settingsPlugin !== false && $settingsPluginVer !== false){ - - #} Create + save initial from default - #} Following have to be set out of props - $defaultOptions = $this->settingsDefault; - $defaultOptions['settingsID'] = $this->settingsVer; - $defaultOptions['plugin'] = $this->settingsPlugin; - $defaultOptions['version'] = $this->settingsPluginVer; - $defaultOptions['db_version'] = $this->settingsPluginDBVer; - - #} Pass back to settings, and save - $this->settings = $defaultOptions; - $this->saveToDB(); + } + + #} Checks through defaults + existing and adds defaults where unset + function validateAndUpdate() { + + foreach ( $this->settingsDefault as $key => $val ) { + if ( ! isset( $this->settings[ $key ] ) ) { + $this->update( $key, $val ); + } + } + } + + #} Initial Create + function initCreate() { + + #} If properly initialised! + if ( $settingsKey !== false && $settingsVer !== false && $settingsDefault !== false && $settingsPlugin !== false && $settingsPluginVer !== false ) { + + #} Create + save initial from default + #} Following have to be set out of props + $defaultOptions = $this->settingsDefault; + $defaultOptions['settingsID'] = $this->settingsVer; + $defaultOptions['plugin'] = $this->settingsPlugin; + $defaultOptions['version'] = $this->settingsPluginVer; + $defaultOptions['db_version'] = $this->settingsPluginDBVer; + + #} Pass back to settings, and save + $this->settings = $defaultOptions; + $this->saveToDB(); #} else brutal exit! - } else exit('WHConfigLib initiated incorrectly.'); - + } else { + exit( 'WHConfigLib initiated incorrectly.' ); } + } + + #} Reset to defaults + function resetToDefaults() { + + #} reset to default opts + #} NOW with added protection :) any protected field keys wont get re-written + + #} Copy any protected keys over the new reset settings (if is set) + $existingSettings = $this->settings; + $newSettings = $this->settingsDefault; + if ( isset( $this->settingsProtected ) && is_array( $this->settingsProtected ) ) { + foreach ( $this->settingsProtected as $protectedKey ) { - #} Reset to defaults - function resetToDefaults(){ - - #} reset to default opts - #} NOW with added protection :) any protected field keys wont get re-written - - #} Copy any protected keys over the new reset settings (if is set) - $existingSettings = $this->settings; - $newSettings = $this->settingsDefault; - if (isset($this->settingsProtected) && is_array($this->settingsProtected)) foreach ($this->settingsProtected as $protectedKey){ - #} If isset - if (isset($existingSettings[$protectedKey])){ + if ( isset( $existingSettings[ $protectedKey ] ) ) { #} Pass it along - $newSettings[$protectedKey] = $existingSettings[$protectedKey]; + $newSettings[ $protectedKey ] = $existingSettings[ $protectedKey ]; } } + } - #} Save em down - $this->settings = $newSettings; - $this->saveToDB(); + #} Save em down + $this->settings = $newSettings; + $this->saveToDB(); + } + + #} Get all options as object + function getAll( $hardRefresh = false ) { + if ( $hardRefresh ) { + $this->loadFromDB(); } - - #} Get all options as object - function getAll($hardRefresh=false){ - - if ($hardRefresh) $this->loadFromDB(); - return $this->settings; - + return $this->settings; + } + + #} Get single option + function get( $key, $freshFromDB = false ) { + + if ( empty( $key ) === true ) { + return false; } - - #} Get single option - function get($key,$freshFromDB=false){ - - if (empty($key) === true) return false; - global $zbs; - // db-loading way (ONLY WORKS DB2!) - return $zbs->DAL->getSetting(array('key' => $key,'fullDetails' => false)); + global $zbs; + // db-loading way (ONLY WORKS DB2!) + return $zbs->DAL->getSetting( + array( + 'key' => $key, + 'fullDetails' => false, + ) + ); + } + + #} Add/Update *brutally + function update( $key, $val = '' ) { + + if ( empty( $key ) === true ) { + return false; } - - #} Add/Update *brutally - function update($key,$val=''){ - - if (empty($key) === true) return false; - global $zbs; + global $zbs; - #} Don't even check existence as I guess it doesn't matter? - $this->settings[$key] = $val; - $zbs->DAL->updateSetting($key, $val); - - } - - #} Delete option - function delete($key){ - - if (empty($key) === true) return false; - - // remove from settings - unset( $this->settings[$key] ); - - // delete from db - global $zbs; - return $zbs->DAL->deleteSetting( array('key' => $key) ); - + #} Don't even check existence as I guess it doesn't matter? + $this->settings[ $key ] = $val; + $zbs->DAL->updateSetting( $key, $val ); + } + + #} Delete option + function delete( $key ) { + + if ( empty( $key ) === true ) { + return false; } + // remove from settings + unset( $this->settings[ $key ] ); - #} ================================== - #} DMZ Config additions - #} 2 layers: - #} DMZConfig = whole object - #} DMZConfigValue = object.value - #} ================================== + // delete from db + global $zbs; + return $zbs->DAL->deleteSetting( array( 'key' => $key ) ); + } + #} ================================== + #} DMZ Config additions + #} 2 layers: + #} DMZConfig = whole object + #} DMZConfigValue = object.value + #} ================================== - #} Get all DMZ (temp func for migration routine DB2, not to be generally used) - function dmzGetMigrationSet(){ - - return array($this->settingsDMZKey,$this->settingsDMZRegister,$this->settingsDMZ); - - } + #} Get all DMZ (temp func for migration routine DB2, not to be generally used) + function dmzGetMigrationSet() { - #} Get single option - function dmzGet($dmzKey,$confKey){ - - if (empty($dmzKey) === true || empty($confKey) === true) return false; - - #} Assumes it's loaded!? - if (isset($this->settingsDMZ[$dmzKey])){ + return array( $this->settingsDMZKey, $this->settingsDMZRegister, $this->settingsDMZ ); + } - if (isset($this->settingsDMZ[$dmzKey][$confKey])) { + #} Get single option + function dmzGet( $dmzKey, $confKey ) { - return $this->settingsDMZ[$dmzKey][$confKey]; + if ( empty( $dmzKey ) === true || empty( $confKey ) === true ) { + return false; + } - } + #} Assumes it's loaded!? + if ( isset( $this->settingsDMZ[ $dmzKey ] ) ) { + + if ( isset( $this->settingsDMZ[ $dmzKey ][ $confKey ] ) ) { + + return $this->settingsDMZ[ $dmzKey ][ $confKey ]; + + } + } + + return false; + } + + #} Delete option + function dmzDelete( $dmzKey, $confKey ) { - } - + if ( empty( $dmzKey ) === true || empty( $confKey ) === true ) { return false; - - } - - #} Delete option - function dmzDelete($dmzKey,$confKey){ - - if (empty($dmzKey) === true || empty($confKey) === true) return false; - - $existingSettings = $this->dmzGetConfig($dmzKey); - $newSettings = array(); - if (isset($existingSettings) && is_array($existingSettings)) { foreach($existingSettings as $k => $v) { - if ($k != $confKey) $newSettings[$k] = $v; + } + + $existingSettings = $this->dmzGetConfig( $dmzKey ); + $newSettings = array(); + if ( isset( $existingSettings ) && is_array( $existingSettings ) ) { + foreach ( $existingSettings as $k => $v ) { + if ( $k != $confKey ) { + $newSettings[ $k ] = $v; } } - - #} Brutal - $this->settingsDMZ[$dmzKey] = $newSettings; - - #} Save down - $this->saveToDB(); - } - - #} Add/Update *brutally - function dmzUpdate($dmzKey,$confKey,$val=''){ - - if (empty($dmzKey) === true || empty($confKey) === true) return false; - - #} if not set, create - if (!isset($this->settingsDMZ[$dmzKey])){ - #} add to register - $this->settingsDMZRegister[$dmzKey] = $dmzKey; + #} Brutal + $this->settingsDMZ[ $dmzKey ] = $newSettings; - #} Create as arr - $this->settingsDMZ[$dmzKey] = array(); + #} Save down + $this->saveToDB(); + } - } + #} Add/Update *brutally + function dmzUpdate( $dmzKey, $confKey, $val = '' ) { - #} Don't even check existence as I guess it doesn't matter? - $this->settingsDMZ[$dmzKey][$confKey] = $val; - - #} Save down - $this->saveToDB(); + if ( empty( $dmzKey ) === true || empty( $confKey ) === true ) { + return false; } - - #} Get alls option - function dmzGetConfig($dmzKey){ - - if (empty($dmzKey) === true) return false; - - #} Assumes it's loaded!? - if (isset($this->settingsDMZ[$dmzKey])){ - - return $this->settingsDMZ[$dmzKey]; - - } - + + #} if not set, create + if ( ! isset( $this->settingsDMZ[ $dmzKey ] ) ) { + + #} add to register + $this->settingsDMZRegister[ $dmzKey ] = $dmzKey; + + #} Create as arr + $this->settingsDMZ[ $dmzKey ] = array(); + + } + + #} Don't even check existence as I guess it doesn't matter? + $this->settingsDMZ[ $dmzKey ][ $confKey ] = $val; + + #} Save down + $this->saveToDB(); + } + + #} Get alls option + function dmzGetConfig( $dmzKey ) { + + if ( empty( $dmzKey ) === true ) { return false; - - } - - #} Delete Config - function dmzDeleteConfig($dmzKey){ - - if (empty($dmzKey) === true) return false; - - #} Brutal - unset($this->settingsDMZ[$dmzKey]); - unset($this->settingsDMZRegister[$dmzKey]); - - #} Save down - $this->saveToDB(); - - } - - #} Add/Update Config *brutally - function dmzUpdateConfig($dmzKey,$config){ - - if (empty($dmzKey) === true || empty($config) === true) return false; - - #} if not set, create - if (!isset($this->settingsDMZ[$dmzKey])){ - - #} add to register - $this->settingsDMZRegister[$dmzKey] = $dmzKey; + } - } + #} Assumes it's loaded!? + if ( isset( $this->settingsDMZ[ $dmzKey ] ) ) { - // DEBUG echo 'type "'.$this->settingsDMZRegister.'" = "'.$dmzKey.'" ("'.gettype($this->settingsDMZRegister).'")
'; + return $this->settingsDMZ[ $dmzKey ]; - #} Just brutally override - $this->settingsDMZ[$dmzKey] = $config; - - #} Save down - $this->saveToDB(); - } - - #} Load/Reload DMZ options from db - function loadDMZFromDB(){ + } - global $zbs; + return false; + } - #} Load the register - $this->settingsDMZRegister = $zbs->DAL->setting($this->settingsDMZKey,array()); + #} Delete Config + function dmzDeleteConfig( $dmzKey ) { - // DEBUG echo 'loaded reg = "'; print_r($this->settingsDMZRegister); echo '"!'; + if ( empty( $dmzKey ) === true ) { + return false; + } - #} This catches weirdo mis-saves?! - if (!is_array($this->settingsDMZRegister)) $this->settingsDMZRegister = array(); + #} Brutal + unset( $this->settingsDMZ[ $dmzKey ] ); + unset( $this->settingsDMZRegister[ $dmzKey ] ); - #} Load anything logged in register - if (is_array($this->settingsDMZRegister) && count($this->settingsDMZRegister) > 0) { foreach ($this->settingsDMZRegister as $regEntry){ + #} Save down + $this->saveToDB(); + } - #} Load it - $this->settingsDMZ[$regEntry] = $zbs->DAL->setting($this->settingsDMZKey.'_'.$regEntry); + #} Add/Update Config *brutally + function dmzUpdateConfig( $dmzKey, $config ) { - } - } - return $this->settingsDMZ; + if ( empty( $dmzKey ) === true || empty( $config ) === true ) { + return false; } - #} / DMZ Fields + #} if not set, create + if ( ! isset( $this->settingsDMZ[ $dmzKey ] ) ) { + #} add to register + $this->settingsDMZRegister[ $dmzKey ] = $dmzKey; - - #} Save back to db - function saveToDB(){ + } - global $zbs; - - // DAL2 saves individually :) - $u = array(); - if (count($this->settings) > 0) foreach ($this->settings as $settingKey => $settingVal){ + // DEBUG echo 'type "'.$this->settingsDMZRegister.'" = "'.$dmzKey.'" ("'.gettype($this->settingsDMZRegister).'")
'; - $u[] = $zbs->DAL->updateSetting($settingKey, $settingVal); + #} Just brutally override + $this->settingsDMZ[ $dmzKey ] = $config; - } + #} Save down + $this->saveToDB(); + } - #} Also any DMZ's! (Brutal big saves - whole objs) + #} Load/Reload DMZ options from db + function loadDMZFromDB() { - #} save register - $zbs->DAL->updateSetting($this->settingsDMZKey,$this->settingsDMZRegister); - // DEBUG echo 'saved dmzregister:'; print_r($this->settingsDMZRegister); echo '!'; - if (isset($this->settingsDMZRegister) && is_array($this->settingsDMZRegister)) foreach ($this->settingsDMZRegister as $dmzKey){ # => $dmzVal + global $zbs; - $u[] = $zbs->DAL->updateSetting($this->settingsDMZKey.'_'.$dmzKey, $this->settingsDMZ[$dmzKey]); + #} Load the register + $this->settingsDMZRegister = $zbs->DAL->setting( $this->settingsDMZKey, array() ); - } + // DEBUG echo 'loaded reg = "'; print_r($this->settingsDMZRegister); echo '"!'; - return $u; - + #} This catches weirdo mis-saves?! + if ( ! is_array( $this->settingsDMZRegister ) ) { + $this->settingsDMZRegister = array(); } - - #} Load/Reload from db - function loadFromDB(){ - global $zbs; + #} Load anything logged in register + if ( is_array( $this->settingsDMZRegister ) && count( $this->settingsDMZRegister ) > 0 ) { + foreach ( $this->settingsDMZRegister as $regEntry ) { - $this->settings = $zbs->DAL->getSettings(array('autoloadOnly' => true,'fullDetails' => false)); - return $this->settings; - - } - - #} Uninstall func - effectively creates a bk then removes its main setting - function uninstall(){ - - #} Set uninstall flag - $this->settings['uninstall'] = time(); - - #} Backup - $this->createBackup('Pre-UnInstall Backup'); - - #} Blank it out - $this->settings = NULL; - - // DAL2 - // leave for now - return true; + #} Load it + $this->settingsDMZ[ $regEntry ] = $zbs->DAL->setting( $this->settingsDMZKey . '_' . $regEntry ); + } } - - #} Backup existing settings obj (ripped from sgv2.0) - function createBackup($backupLabel=''){ - - // Left this the same for DAL2 - is still storing backups in wp db - - $existingBK = get_option($this->settingsKey.'_bk'); if (!is_array($existingBK)) $existingBK = array(); - $existingBK[time()] = array( - 'main' => $this->settings, - 'dmzreg' => $this->settingsDMZRegister, - 'dmz' => $this->settingsDMZ - ); - if (!empty($backupLabel)) $existingBK[time()]['backupLabel'] = sanitize_text_field($backupLabel); #} For named settings bk - update_option($this->settingsKey.'_bk',$existingBK, false); - return $existingBK[time()]; - + return $this->settingsDMZ; + } + + #} / DMZ Fields + + #} Save back to db + function saveToDB() { + + global $zbs; + + // DAL2 saves individually :) + $u = array(); + if ( count( $this->settings ) > 0 ) { + foreach ( $this->settings as $settingKey => $settingVal ) { + + $u[] = $zbs->DAL->updateSetting( $settingKey, $settingVal ); + + } } - - #} Kills all bks - function killBackups(){ - - return delete_option($this->settingsKey.'_bk'); - + + #} Also any DMZ's! (Brutal big saves - whole objs) + + #} save register + $zbs->DAL->updateSetting( $this->settingsDMZKey, $this->settingsDMZRegister ); + // DEBUG echo 'saved dmzregister:'; print_r($this->settingsDMZRegister); echo '!'; + if ( isset( $this->settingsDMZRegister ) && is_array( $this->settingsDMZRegister ) ) { + foreach ( $this->settingsDMZRegister as $dmzKey ) { # => $dmzVal + + $u[] = $zbs->DAL->updateSetting( $this->settingsDMZKey . '_' . $dmzKey, $this->settingsDMZ[ $dmzKey ] ); + + } } - - #} Retrieve BKs - function getBKs(){ - - $x = get_option($this->settingsKey.'_bk'); - - if (is_array($x)) return $x; else return array(); - + + return $u; + } + + #} Load/Reload from db + function loadFromDB() { + + global $zbs; + + $this->settings = $zbs->DAL->getSettings( + array( + 'autoloadOnly' => true, + 'fullDetails' => false, + ) + ); + return $this->settings; + } + + #} Uninstall func - effectively creates a bk then removes its main setting + function uninstall() { + + #} Set uninstall flag + $this->settings['uninstall'] = time(); + + #} Backup + $this->createBackup( 'Pre-UnInstall Backup' ); + + #} Blank it out + $this->settings = null; + + // DAL2 + // leave for now + return true; + } + + #} Backup existing settings obj (ripped from sgv2.0) + function createBackup( $backupLabel = '' ) { + + // Left this the same for DAL2 - is still storing backups in wp db + + $existingBK = get_option( $this->settingsKey . '_bk' ); + if ( ! is_array( $existingBK ) ) { + $existingBK = array(); } - - #} Reload from BK (bkkey will be a timestamp, use getBKs to list these keys) - function reloadFromBK($bkkey){ - - $backups = get_option($this->settingsKey.'_bk'); - - if (isset($backups[$bkkey])) if (is_array($backups[$bkkey])) { - - #} kill existing settings and use backed up ones - $this->settings = $backups[$bkkey]; - - #} Save - $this->saveToDB(); - - return true; - - } - - return false; - - + $existingBK[ time() ] = array( + 'main' => $this->settings, + 'dmzreg' => $this->settingsDMZRegister, + 'dmz' => $this->settingsDMZ, + ); + if ( ! empty( $backupLabel ) ) { + $existingBK[ time() ]['backupLabel'] = sanitize_text_field( $backupLabel ); #} For named settings bk } + update_option( $this->settingsKey . '_bk', $existingBK, false ); + return $existingBK[ time() ]; } + #} Kills all bks + function killBackups() { - #} This is a wrapper/factory class which simplifies using DMZ fields for extension plugins - class WHWPConfigExtensionsLib { - - #} key holder - private $extperma = false; - private $settingsObj = false; - private $existingSettings = false; - - #} Constructor - function __construct($extperma='',$defaultConfig=array()) { - - if (!empty($extperma)){ - - #} store - $this->extperma = 'ext_'.$extperma; - - #} initiate settings obj as a dmz set - // WH move to $zbs->settings - // ALSO now covered by // LEGACY SUPPORT (see ZeroBSCRM.php) - global $zbs; - - if (isset($zbs->settings) && !empty($zbs->settings)){ - - $existingSettings = $zbs->settings->dmzGetConfig($this->extperma); - - } else { - - // legacy - older plugins not using new init hooks - // pass back empty for now (will break them) - // and notify - $existingSettings = array(); - - // notify - // can't do directly, as this is PRE INIT (no logged in user) - // so delay... zeroBSCRM_notifyme_insert_notification(get_current_user_id(),-999,-1,'extension.update'); - // weird this doesn't work either... day of it.add_action('before_zerobscrm_init', 'zeroBS_temp_ext_legacy_notice'); - // gonna do this grossly: - if (!defined('ZBSTEMPLEGACYNOTICE')) define('ZBSTEMPLEGACYNOTICE',1); - - // this is a hotfix 2.50.1 to work with // LEGACY SUPPORT - // ... it'll add the setting to a pile to be reconstructed post init :) - global $zbsLegacySupport; - $zbsLegacySupport['extsettingspostinit'][$this->extperma] = $defaultConfig; - - } - - #} Create if not existing - if (!is_array($existingSettings)){ - - #} init - $zbs->settings->dmzUpdateConfig($this->extperma,$defaultConfig); + return delete_option( $this->settingsKey . '_bk' ); + } - } + #} Retrieve BKs + function getBKs() { - } else exit('WHConfigLib initiated incorrectly.'); + $x = get_option( $this->settingsKey . '_bk' ); + if ( is_array( $x ) ) { + return $x; + } else { + return array(); } + } - #} passthrough funcs + #} Reload from BK (bkkey will be a timestamp, use getBKs to list these keys) + function reloadFromBK( $bkkey ) { - function get($key){ + $backups = get_option( $this->settingsKey . '_bk' ); - //global $zbs; - //return $zeroBSCRM_Settings->dmzGet($this->extperma,$key); + if ( isset( $backups[ $bkkey ] ) ) { + if ( is_array( $backups[ $bkkey ] ) ) { - // WH move to $zbs->settings - global $zbs; - return $zbs->settings->dmzGet($this->extperma,$key); + #} kill existing settings and use backed up ones + $this->settings = $backups[ $bkkey ]; + #} Save + $this->saveToDB(); + + return true; + + } } - function delete($key){ + return false; + } +} - //global $zbs; - //return $zeroBSCRM_Settings->dmzDelete($this->extperma,$key); + #} This is a wrapper/factory class which simplifies using DMZ fields for extension plugins +class WHWPConfigExtensionsLib { + #} key holder + private $extperma = false; + private $settingsObj = false; + private $existingSettings = false; + + #} Constructor + function __construct( $extperma = '', $defaultConfig = array() ) { + + if ( ! empty( $extperma ) ) { + + #} store + $this->extperma = 'ext_' . $extperma; + + #} initiate settings obj as a dmz set // WH move to $zbs->settings + // ALSO now covered by // LEGACY SUPPORT (see ZeroBSCRM.php) global $zbs; - return $zbs->settings->dmzDelete($this->extperma,$key); + if ( isset( $zbs->settings ) && ! empty( $zbs->settings ) ) { - } + $existingSettings = $zbs->settings->dmzGetConfig( $this->extperma ); - function update($key,$val=''){ + } else { - //global $zbs; - //return $zeroBSCRM_Settings->dmzUpdate($this->extperma,$key,$val); + // legacy - older plugins not using new init hooks + // pass back empty for now (will break them) + // and notify + $existingSettings = array(); - // WH move to $zbs->settings - global $zbs; - return $zbs->settings->dmzUpdate($this->extperma,$key,$val); + // notify + // can't do directly, as this is PRE INIT (no logged in user) + // so delay... zeroBSCRM_notifyme_insert_notification(get_current_user_id(),-999,-1,'extension.update'); + // weird this doesn't work either... day of it.add_action('before_zerobscrm_init', 'zeroBS_temp_ext_legacy_notice'); + // gonna do this grossly: + if ( ! defined( 'ZBSTEMPLEGACYNOTICE' ) ) { + define( 'ZBSTEMPLEGACYNOTICE', 1 ); + } + + // this is a hotfix 2.50.1 to work with // LEGACY SUPPORT + // ... it'll add the setting to a pile to be reconstructed post init :) + global $zbsLegacySupport; + $zbsLegacySupport['extsettingspostinit'][ $this->extperma ] = $defaultConfig; + + } + #} Create if not existing + if ( ! is_array( $existingSettings ) ) { + #} init + $zbs->settings->dmzUpdateConfig( $this->extperma, $defaultConfig ); + + } + } else { + exit( 'WHConfigLib initiated incorrectly.' ); } + } - function getAll(){ + #} passthrough funcs - //global $zbs; - //return $zeroBSCRM_Settings->dmzGetConfig($this->extperma); + function get( $key ) { - // WH move to $zbs->settings - global $zbs; - return $zbs->settings->dmzGetConfig($this->extperma); + // global $zbs; + // return $zeroBSCRM_Settings->dmzGet($this->extperma,$key); - } + // WH move to $zbs->settings + global $zbs; + return $zbs->settings->dmzGet( $this->extperma, $key ); } + function delete( $key ) { + + // global $zbs; + // return $zeroBSCRM_Settings->dmzDelete($this->extperma,$key); + + // WH move to $zbs->settings + global $zbs; + return $zbs->settings->dmzDelete( $this->extperma, $key ); + } + + function update( $key, $val = '' ) { + + // global $zbs; + // return $zeroBSCRM_Settings->dmzUpdate($this->extperma,$key,$val); + + // WH move to $zbs->settings + global $zbs; + return $zbs->settings->dmzUpdate( $this->extperma, $key, $val ); + } + + function getAll() { + + // global $zbs; + // return $zeroBSCRM_Settings->dmzGetConfig($this->extperma); + + // WH move to $zbs->settings + global $zbs; + return $zbs->settings->dmzGetConfig( $this->extperma ); + } +} -function zeroBS_temp_ext_legacy_notice(){ +function zeroBS_temp_ext_legacy_notice() { // add one menu item, even if multiple ext. - if (!defined('ZBSLEGACYSET')){ - $o = get_option('zbs_temp_legacy_update_msg'); - if ($o == false){ - zeroBSCRM_notifyme_insert_notification(get_current_user_id(),-999,-1,'extension.update'); - update_option('zbs_temp_legacy_update_msg',1, false); + if ( ! defined( 'ZBSLEGACYSET' ) ) { + $o = get_option( 'zbs_temp_legacy_update_msg' ); + if ( $o == false ) { + zeroBSCRM_notifyme_insert_notification( get_current_user_id(), -999, -1, 'extension.update' ); + update_option( 'zbs_temp_legacy_update_msg', 1, false ); } - define('ZBSLEGACYSET',1); + define( 'ZBSLEGACYSET', 1 ); } -} +} diff --git a/projects/plugins/crm/includes/wh.countries.lib.php b/projects/plugins/crm/includes/wh.countries.lib.php index 463991ca431d..d8788651bab2 100644 --- a/projects/plugins/crm/includes/wh.countries.lib.php +++ b/projects/plugins/crm/includes/wh.countries.lib.php @@ -1,5 +1,5 @@ - 'Afghanistan', - 'AX' => 'Aland Islands', - 'AL' => 'Albania', - 'DZ' => 'Algeria', - 'AS' => 'American Samoa', - 'AD' => 'Andorra', - 'AO' => 'Angola', - 'AI' => 'Anguilla', - 'AQ' => 'Antarctica', - 'AG' => 'Antigua and Barbuda', - 'AR' => 'Argentina', - 'AM' => 'Armenia', - 'AW' => 'Aruba', - 'AU' => 'Australia', - 'AT' => 'Austria', - 'AZ' => 'Azerbaijan', - 'BS' => 'Bahamas', - 'BH' => 'Bahrain', - 'BD' => 'Bangladesh', - 'BB' => 'Barbados', - 'BY' => 'Belarus', - 'BE' => 'Belgium', - 'BZ' => 'Belize', - 'BJ' => 'Benin', - 'BM' => 'Bermuda', - 'BT' => 'Bhutan', - 'BO' => 'Bolivia', - 'BQ' => 'Bonaire, Saint Eustatius and Saba', - 'BA' => 'Bosnia and Herzegovina', - 'BW' => 'Botswana', - 'BV' => 'Bouvet Island', - 'BR' => 'Brazil', - 'IO' => 'British Indian Ocean Territory', - 'VG' => 'British Virgin Islands', - 'BN' => 'Brunei', - 'BG' => 'Bulgaria', - 'BF' => 'Burkina Faso', - 'BI' => 'Burundi', - 'KH' => 'Cambodia', - 'CM' => 'Cameroon', - 'CA' => 'Canada', - 'CV' => 'Cape Verde', - 'KY' => 'Cayman Islands', - 'CF' => 'Central African Republic', - 'TD' => 'Chad', - 'CL' => 'Chile', - 'CN' => 'China', - 'CX' => 'Christmas Island', - 'CC' => 'Cocos Islands', - 'CO' => 'Colombia', - 'KM' => 'Comoros', - 'CK' => 'Cook Islands', - 'CR' => 'Costa Rica', - 'HR' => 'Croatia', - 'CU' => 'Cuba', - 'CW' => 'Curacao', - 'CY' => 'Cyprus', - 'CZ' => 'Czech Republic', - 'CD' => 'Democratic Republic of the Congo', - 'DK' => 'Denmark', - 'DJ' => 'Djibouti', - 'DM' => 'Dominica', - 'DO' => 'Dominican Republic', - 'TL' => 'East Timor', - 'EC' => 'Ecuador', - 'EG' => 'Egypt', - 'SV' => 'El Salvador', - 'GQ' => 'Equatorial Guinea', - 'ER' => 'Eritrea', - 'EE' => 'Estonia', - 'ET' => 'Ethiopia', - 'FK' => 'Falkland Islands', - 'FO' => 'Faroe Islands', - 'FJ' => 'Fiji', - 'FI' => 'Finland', - 'FR' => 'France', - 'GF' => 'French Guiana', - 'PF' => 'French Polynesia', - 'TF' => 'French Southern Territories', - 'GA' => 'Gabon', - 'GM' => 'Gambia', - 'GE' => 'Georgia', - 'DE' => 'Germany', - 'GH' => 'Ghana', - 'GI' => 'Gibraltar', - 'GR' => 'Greece', - 'GL' => 'Greenland', - 'GD' => 'Grenada', - 'GP' => 'Guadeloupe', - 'GU' => 'Guam', - 'GT' => 'Guatemala', - 'GG' => 'Guernsey', - 'GN' => 'Guinea', - 'GW' => 'Guinea-Bissau', - 'GY' => 'Guyana', - 'HT' => 'Haiti', - 'HM' => 'Heard Island and McDonald Islands', - 'HN' => 'Honduras', - 'HK' => 'Hong Kong', - 'HU' => 'Hungary', - 'IS' => 'Iceland', - 'IN' => 'India', - 'ID' => 'Indonesia', - 'IR' => 'Iran', - 'IQ' => 'Iraq', - 'IE' => 'Ireland', - 'IM' => 'Isle of Man', - 'IL' => 'Israel', - 'IT' => 'Italy', - 'CI' => 'Ivory Coast', - 'JM' => 'Jamaica', - 'JP' => 'Japan', - 'JE' => 'Jersey', - 'JO' => 'Jordan', - 'KZ' => 'Kazakhstan', - 'KE' => 'Kenya', - 'KI' => 'Kiribati', - 'XK' => 'Kosovo', - 'KW' => 'Kuwait', - 'KG' => 'Kyrgyzstan', - 'LA' => 'Laos', - 'LV' => 'Latvia', - 'LB' => 'Lebanon', - 'LS' => 'Lesotho', - 'LR' => 'Liberia', - 'LY' => 'Libya', - 'LI' => 'Liechtenstein', - 'LT' => 'Lithuania', - 'LU' => 'Luxembourg', - 'MO' => 'Macao', - 'MK' => 'Macedonia', - 'MG' => 'Madagascar', - 'MW' => 'Malawi', - 'MY' => 'Malaysia', - 'MV' => 'Maldives', - 'ML' => 'Mali', - 'MT' => 'Malta', - 'MH' => 'Marshall Islands', - 'MQ' => 'Martinique', - 'MR' => 'Mauritania', - 'MU' => 'Mauritius', - 'YT' => 'Mayotte', - 'MX' => 'Mexico', - 'FM' => 'Micronesia', - 'MD' => 'Moldova', - 'MC' => 'Monaco', - 'MN' => 'Mongolia', - 'ME' => 'Montenegro', - 'MS' => 'Montserrat', - 'MA' => 'Morocco', - 'MZ' => 'Mozambique', - 'MM' => 'Myanmar', - 'NA' => 'Namibia', - 'NR' => 'Nauru', - 'NP' => 'Nepal', - 'NL' => 'Netherlands', - 'NC' => 'New Caledonia', - 'NZ' => 'New Zealand', - 'NI' => 'Nicaragua', - 'NE' => 'Niger', - 'NG' => 'Nigeria', - 'NU' => 'Niue', - 'NF' => 'Norfolk Island', - 'KP' => 'North Korea', - 'MP' => 'Northern Mariana Islands', - 'NO' => 'Norway', - 'OM' => 'Oman', - 'PK' => 'Pakistan', - 'PW' => 'Palau', - 'PS' => 'Palestinian Territory', - 'PA' => 'Panama', - 'PG' => 'Papua New Guinea', - 'PY' => 'Paraguay', - 'PE' => 'Peru', - 'PH' => 'Philippines', - 'PN' => 'Pitcairn', - 'PL' => 'Poland', - 'PT' => 'Portugal', - 'PR' => 'Puerto Rico', - 'QA' => 'Qatar', - 'CG' => 'Republic of the Congo', - 'RE' => 'Reunion', - 'RO' => 'Romania', - 'RU' => 'Russia', - 'RW' => 'Rwanda', - 'BL' => 'Saint Barthelemy', - 'SH' => 'Saint Helena', - 'KN' => 'Saint Kitts and Nevis', - 'LC' => 'Saint Lucia', - 'MF' => 'Saint Martin', - 'PM' => 'Saint Pierre and Miquelon', - 'VC' => 'Saint Vincent and the Grenadines', - 'WS' => 'Samoa', - 'SM' => 'San Marino', - 'ST' => 'Sao Tome and Principe', - 'SA' => 'Saudi Arabia', - 'SN' => 'Senegal', - 'RS' => 'Serbia', - 'SC' => 'Seychelles', - 'SL' => 'Sierra Leone', - 'SG' => 'Singapore', - 'SX' => 'Sint Maarten', - 'SK' => 'Slovakia', - 'SI' => 'Slovenia', - 'SB' => 'Solomon Islands', - 'SO' => 'Somalia', - 'ZA' => 'South Africa', - 'GS' => 'South Georgia and the South Sandwich Islands', - 'KR' => 'South Korea', - 'SS' => 'South Sudan', - 'ES' => 'Spain', - 'LK' => 'Sri Lanka', - 'SD' => 'Sudan', - 'SR' => 'Suriname', - 'SJ' => 'Svalbard and Jan Mayen', - 'SZ' => 'Swaziland', - 'SE' => 'Sweden', - 'CH' => 'Switzerland', - 'SY' => 'Syria', - 'TW' => 'Taiwan', - 'TJ' => 'Tajikistan', - 'TZ' => 'Tanzania', - 'TH' => 'Thailand', - 'TG' => 'Togo', - 'TK' => 'Tokelau', - 'TO' => 'Tonga', - 'TT' => 'Trinidad and Tobago', - 'TN' => 'Tunisia', - 'TR' => 'Turkey', - 'TM' => 'Turkmenistan', - 'TC' => 'Turks and Caicos Islands', - 'TV' => 'Tuvalu', - 'VI' => 'U.S. Virgin Islands', - 'UG' => 'Uganda', - 'UA' => 'Ukraine', - 'AE' => 'United Arab Emirates', - 'GB' => 'United Kingdom', - 'US' => 'United States', - 'UM' => 'United States Minor Outlying Islands', - 'UY' => 'Uruguay', - 'UZ' => 'Uzbekistan', - 'VU' => 'Vanuatu', - 'VA' => 'Vatican', - 'VE' => 'Venezuela', - 'VN' => 'Vietnam', - 'WF' => 'Wallis and Futuna', - 'EH' => 'Western Sahara', - 'YE' => 'Yemen', - 'ZM' => 'Zambia', - 'ZW' => 'Zimbabwe', + 'AF' => 'Afghanistan', + 'AX' => 'Aland Islands', + 'AL' => 'Albania', + 'DZ' => 'Algeria', + 'AS' => 'American Samoa', + 'AD' => 'Andorra', + 'AO' => 'Angola', + 'AI' => 'Anguilla', + 'AQ' => 'Antarctica', + 'AG' => 'Antigua and Barbuda', + 'AR' => 'Argentina', + 'AM' => 'Armenia', + 'AW' => 'Aruba', + 'AU' => 'Australia', + 'AT' => 'Austria', + 'AZ' => 'Azerbaijan', + 'BS' => 'Bahamas', + 'BH' => 'Bahrain', + 'BD' => 'Bangladesh', + 'BB' => 'Barbados', + 'BY' => 'Belarus', + 'BE' => 'Belgium', + 'BZ' => 'Belize', + 'BJ' => 'Benin', + 'BM' => 'Bermuda', + 'BT' => 'Bhutan', + 'BO' => 'Bolivia', + 'BQ' => 'Bonaire, Saint Eustatius and Saba', + 'BA' => 'Bosnia and Herzegovina', + 'BW' => 'Botswana', + 'BV' => 'Bouvet Island', + 'BR' => 'Brazil', + 'IO' => 'British Indian Ocean Territory', + 'VG' => 'British Virgin Islands', + 'BN' => 'Brunei', + 'BG' => 'Bulgaria', + 'BF' => 'Burkina Faso', + 'BI' => 'Burundi', + 'KH' => 'Cambodia', + 'CM' => 'Cameroon', + 'CA' => 'Canada', + 'CV' => 'Cape Verde', + 'KY' => 'Cayman Islands', + 'CF' => 'Central African Republic', + 'TD' => 'Chad', + 'CL' => 'Chile', + 'CN' => 'China', + 'CX' => 'Christmas Island', + 'CC' => 'Cocos Islands', + 'CO' => 'Colombia', + 'KM' => 'Comoros', + 'CK' => 'Cook Islands', + 'CR' => 'Costa Rica', + 'HR' => 'Croatia', + 'CU' => 'Cuba', + 'CW' => 'Curacao', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'CD' => 'Democratic Republic of the Congo', + 'DK' => 'Denmark', + 'DJ' => 'Djibouti', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'TL' => 'East Timor', + 'EC' => 'Ecuador', + 'EG' => 'Egypt', + 'SV' => 'El Salvador', + 'GQ' => 'Equatorial Guinea', + 'ER' => 'Eritrea', + 'EE' => 'Estonia', + 'ET' => 'Ethiopia', + 'FK' => 'Falkland Islands', + 'FO' => 'Faroe Islands', + 'FJ' => 'Fiji', + 'FI' => 'Finland', + 'FR' => 'France', + 'GF' => 'French Guiana', + 'PF' => 'French Polynesia', + 'TF' => 'French Southern Territories', + 'GA' => 'Gabon', + 'GM' => 'Gambia', + 'GE' => 'Georgia', + 'DE' => 'Germany', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GR' => 'Greece', + 'GL' => 'Greenland', + 'GD' => 'Grenada', + 'GP' => 'Guadeloupe', + 'GU' => 'Guam', + 'GT' => 'Guatemala', + 'GG' => 'Guernsey', + 'GN' => 'Guinea', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HT' => 'Haiti', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HK' => 'Hong Kong', + 'HU' => 'Hungary', + 'IS' => 'Iceland', + 'IN' => 'India', + 'ID' => 'Indonesia', + 'IR' => 'Iran', + 'IQ' => 'Iraq', + 'IE' => 'Ireland', + 'IM' => 'Isle of Man', + 'IL' => 'Israel', + 'IT' => 'Italy', + 'CI' => 'Ivory Coast', + 'JM' => 'Jamaica', + 'JP' => 'Japan', + 'JE' => 'Jersey', + 'JO' => 'Jordan', + 'KZ' => 'Kazakhstan', + 'KE' => 'Kenya', + 'KI' => 'Kiribati', + 'XK' => 'Kosovo', + 'KW' => 'Kuwait', + 'KG' => 'Kyrgyzstan', + 'LA' => 'Laos', + 'LV' => 'Latvia', + 'LB' => 'Lebanon', + 'LS' => 'Lesotho', + 'LR' => 'Liberia', + 'LY' => 'Libya', + 'LI' => 'Liechtenstein', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'MO' => 'Macao', + 'MK' => 'Macedonia', + 'MG' => 'Madagascar', + 'MW' => 'Malawi', + 'MY' => 'Malaysia', + 'MV' => 'Maldives', + 'ML' => 'Mali', + 'MT' => 'Malta', + 'MH' => 'Marshall Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MU' => 'Mauritius', + 'YT' => 'Mayotte', + 'MX' => 'Mexico', + 'FM' => 'Micronesia', + 'MD' => 'Moldova', + 'MC' => 'Monaco', + 'MN' => 'Mongolia', + 'ME' => 'Montenegro', + 'MS' => 'Montserrat', + 'MA' => 'Morocco', + 'MZ' => 'Mozambique', + 'MM' => 'Myanmar', + 'NA' => 'Namibia', + 'NR' => 'Nauru', + 'NP' => 'Nepal', + 'NL' => 'Netherlands', + 'NC' => 'New Caledonia', + 'NZ' => 'New Zealand', + 'NI' => 'Nicaragua', + 'NE' => 'Niger', + 'NG' => 'Nigeria', + 'NU' => 'Niue', + 'NF' => 'Norfolk Island', + 'KP' => 'North Korea', + 'MP' => 'Northern Mariana Islands', + 'NO' => 'Norway', + 'OM' => 'Oman', + 'PK' => 'Pakistan', + 'PW' => 'Palau', + 'PS' => 'Palestinian Territory', + 'PA' => 'Panama', + 'PG' => 'Papua New Guinea', + 'PY' => 'Paraguay', + 'PE' => 'Peru', + 'PH' => 'Philippines', + 'PN' => 'Pitcairn', + 'PL' => 'Poland', + 'PT' => 'Portugal', + 'PR' => 'Puerto Rico', + 'QA' => 'Qatar', + 'CG' => 'Republic of the Congo', + 'RE' => 'Reunion', + 'RO' => 'Romania', + 'RU' => 'Russia', + 'RW' => 'Rwanda', + 'BL' => 'Saint Barthelemy', + 'SH' => 'Saint Helena', + 'KN' => 'Saint Kitts and Nevis', + 'LC' => 'Saint Lucia', + 'MF' => 'Saint Martin', + 'PM' => 'Saint Pierre and Miquelon', + 'VC' => 'Saint Vincent and the Grenadines', + 'WS' => 'Samoa', + 'SM' => 'San Marino', + 'ST' => 'Sao Tome and Principe', + 'SA' => 'Saudi Arabia', + 'SN' => 'Senegal', + 'RS' => 'Serbia', + 'SC' => 'Seychelles', + 'SL' => 'Sierra Leone', + 'SG' => 'Singapore', + 'SX' => 'Sint Maarten', + 'SK' => 'Slovakia', + 'SI' => 'Slovenia', + 'SB' => 'Solomon Islands', + 'SO' => 'Somalia', + 'ZA' => 'South Africa', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'KR' => 'South Korea', + 'SS' => 'South Sudan', + 'ES' => 'Spain', + 'LK' => 'Sri Lanka', + 'SD' => 'Sudan', + 'SR' => 'Suriname', + 'SJ' => 'Svalbard and Jan Mayen', + 'SZ' => 'Swaziland', + 'SE' => 'Sweden', + 'CH' => 'Switzerland', + 'SY' => 'Syria', + 'TW' => 'Taiwan', + 'TJ' => 'Tajikistan', + 'TZ' => 'Tanzania', + 'TH' => 'Thailand', + 'TG' => 'Togo', + 'TK' => 'Tokelau', + 'TO' => 'Tonga', + 'TT' => 'Trinidad and Tobago', + 'TN' => 'Tunisia', + 'TR' => 'Turkey', + 'TM' => 'Turkmenistan', + 'TC' => 'Turks and Caicos Islands', + 'TV' => 'Tuvalu', + 'VI' => 'U.S. Virgin Islands', + 'UG' => 'Uganda', + 'UA' => 'Ukraine', + 'AE' => 'United Arab Emirates', + 'GB' => 'United Kingdom', + 'US' => 'United States', + 'UM' => 'United States Minor Outlying Islands', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VU' => 'Vanuatu', + 'VA' => 'Vatican', + 'VE' => 'Venezuela', + 'VN' => 'Vietnam', + 'WF' => 'Wallis and Futuna', + 'EH' => 'Western Sahara', + 'YE' => 'Yemen', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', ); diff --git a/projects/plugins/crm/includes/wh.currency.lib.php b/projects/plugins/crm/includes/wh.currency.lib.php index 4c5625de796a..e10586319cc0 100644 --- a/projects/plugins/crm/includes/wh.currency.lib.php +++ b/projects/plugins/crm/includes/wh.currency.lib.php @@ -1,5 +1,5 @@ -get_transaction_id_from_give_id( $givewp_donation_id ); // if donor now exists and the transaction ID does not exist, create! - if ( $contact_id && !$transaction_id ) { + if ( $contact_id && ! $transaction_id ) { // build transaction @@ -129,10 +125,12 @@ public function add_donation( $givewp_donation_id, $payment_data ) { ); // add transaction - $transaction_id = $zbs->DAL->transactions->addUpdateTransaction( array( - 'data' => $new_transaction_data, - 'extraMeta' => array( 'givewp_transaction_id' => $givewp_donation_id ), - )); + $transaction_id = $zbs->DAL->transactions->addUpdateTransaction( + array( + 'data' => $new_transaction_data, + 'extraMeta' => array( 'givewp_transaction_id' => $givewp_donation_id ), + ) + ); } } @@ -149,7 +147,7 @@ private function add_update_donor( $givewp_donation_id, $payment_data ) { global $zbs; // inspired by Jetpack Forms implementation - $restricted_keys = array( + $restricted_keys = array( 'externalSources', 'companies', 'lastcontacted', @@ -182,13 +180,13 @@ private function add_update_donor( $givewp_donation_id, $payment_data ) { $new_contact_data['email'] = $v; break; case 'address': - if ( !empty( $v ) ) { - $new_contact_data['addr1'] = $v['line1']; - $new_contact_data['addr2'] = $v['line2']; - $new_contact_data['city'] = $v['city']; - $new_contact_data['county'] = $v['state']; + if ( ! empty( $v ) ) { + $new_contact_data['addr1'] = $v['line1']; + $new_contact_data['addr2'] = $v['line2']; + $new_contact_data['city'] = $v['city']; + $new_contact_data['county'] = $v['state']; $new_contact_data['postcode'] = $v['zip']; - $new_contact_data['country'] = $v['country']; + $new_contact_data['country'] = $v['country']; } break; default: @@ -198,7 +196,7 @@ private function add_update_donor( $givewp_donation_id, $payment_data ) { $data_key = substr( $k, strlen( $jpcrm_field_prefix ) ); if ( ! in_array( $data_key, $restricted_keys, true ) ) { if ( $data_key === 'tags' ) { - $new_contact_data['tags'] = explode( ',', $v ); + $new_contact_data['tags'] = explode( ',', $v ); $new_contact_data['tags'][] = 'GiveWP'; } else { $new_contact_data[ $data_key ] = $v; @@ -223,7 +221,7 @@ private function add_update_donor( $givewp_donation_id, $payment_data ) { ); // log if contact is created by GiveWP - $longdesc = sprintf( __( 'User was created from GiveWP when submitting donation %s through the %s form.', 'zero-bs-crm' ), $givewp_donation_id, '' . $payment_data['give_form_title'] . '' ); + $longdesc = sprintf( __( 'User was created from GiveWP when submitting donation %1$s through the %2$s form.', 'zero-bs-crm' ), $givewp_donation_id, '' . $payment_data['give_form_title'] . '' ); $created_meta = array( 'note_override' => array( @@ -234,7 +232,7 @@ private function add_update_donor( $givewp_donation_id, $payment_data ) { ); // log if GiveWP transaction was added to this contact - $longdesc = sprintf( __( 'A GiveWP donation was submitted by this user via the %s form.', 'zero-bs-crm' ), '' . $payment_data['give_form_title'] . '' ); + $longdesc = sprintf( __( 'A GiveWP donation was submitted by this user via the %s form.', 'zero-bs-crm' ), '' . $payment_data['give_form_title'] . '' ); $exists_meta = array( 'type' => __( 'Form filled', 'zero-bs-crm' ), 'shortdesc' => __( 'Donation via GiveWP', 'zero-bs-crm' ), @@ -259,7 +257,7 @@ private function add_update_donor( $givewp_donation_id, $payment_data ) { * * This is hooked into the 'give_update_payment_status' action, which * is run at the end of GiveWP's Give_Payment::update_status() function - * + * * Note that this also runs when a new donation is created * * @param int $givewp_donation_id donation ID @@ -267,7 +265,6 @@ private function add_update_donor( $givewp_donation_id, $payment_data ) { * @param string $old_status old donation status * * @return bool - * */ public function update_donation_status( $givewp_donation_id, $new_status, $old_status ) { @@ -282,7 +279,7 @@ public function update_donation_status( $givewp_donation_id, $new_status, $old_s } // check if transaction exists - $transaction_id = (int)$this->get_transaction_id_from_give_id( $givewp_donation_id ); + $transaction_id = (int) $this->get_transaction_id_from_give_id( $givewp_donation_id ); // update status if transaction exists if ( $transaction_id > 0 ) { @@ -300,10 +297,12 @@ public function update_donation_status( $givewp_donation_id, $new_status, $old_s */ public function get_transaction_id_from_give_id( $givewp_donation_id ) { global $zbs; - return $zbs->DAL->getIDWithMeta( array( - 'objtype' => ZBS_TYPE_TRANSACTION, - 'key' => 'extra_givewp_transaction_id', - 'val' => $givewp_donation_id, - )); + return $zbs->DAL->getIDWithMeta( + array( + 'objtype' => ZBS_TYPE_TRANSACTION, + 'key' => 'extra_givewp_transaction_id', + 'val' => $givewp_donation_id, + ) + ); } } diff --git a/projects/plugins/crm/modules/givewp/jpcrm-givewp-init.php b/projects/plugins/crm/modules/givewp/jpcrm-givewp-init.php index 68ae6dcec9a7..4a6e730f5740 100644 --- a/projects/plugins/crm/modules/givewp/jpcrm-givewp-init.php +++ b/projects/plugins/crm/modules/givewp/jpcrm-givewp-init.php @@ -5,7 +5,7 @@ * This file registers the GiveWP module with core; it's pretty convoluted, * but that's due to a legacy init setup. The goal here is to have all * needed code self-contained in the module's folder. - * + * * If the module is enabled, it is loaded with the jpcrm_load_modules hook */ @@ -47,7 +47,6 @@ function jpcrm_register_external_sources_givewp( $external_sources ) { } add_filter( 'jpcrm_register_external_sources', 'jpcrm_register_external_sources_givewp' ); - global $zeroBSCRM_extensionsCompleteList; $zeroBSCRM_extensionsCompleteList['givewp'] = array( 'fallbackname' => __( 'GiveWP Connector', 'zero-bs-crm' ), @@ -74,8 +73,8 @@ function zeroBSCRM_extension_install_givewp() { $status_to_add = __( 'Donor', 'zero-bs-crm' ); $customised_fields_settings = $zbs->settings->get( 'customisedfields' ); - $contact_statuses = explode( ',', $customised_fields_settings['customers']['status'][1] ); - if ( !in_array( $status_to_add, $contact_statuses ) ) { + $contact_statuses = explode( ',', $customised_fields_settings['customers']['status'][1] ); + if ( ! in_array( $status_to_add, $contact_statuses ) ) { $contact_statuses[] = $status_to_add; } $customised_fields_settings['customers']['status'][1] = implode( ',', $contact_statuses ); @@ -93,7 +92,7 @@ function zeroBSCRM_extension_uninstall_givewp() { function jpcrm_load_givewp() { global $zbs; if ( zeroBSCRM_isExtensionInstalled( 'givewp' ) ) { - require_once( JPCRM_MODULES_PATH . 'givewp/class-jpcrm-givewp.php' ); + require_once JPCRM_MODULES_PATH . 'givewp/class-jpcrm-givewp.php'; // $zbs->givewp = new JPCRM_GiveWP; $zbs->modules->load_module( 'givewp', 'JPCRM_GiveWP' ); } diff --git a/projects/plugins/crm/modules/mailpoet/admin/mailpoet-hub/main.page.php b/projects/plugins/crm/modules/mailpoet/admin/mailpoet-hub/main.page.php index 57791797ae70..c9cf1288c3f2 100644 --- a/projects/plugins/crm/modules/mailpoet/admin/mailpoet-hub/main.page.php +++ b/projects/plugins/crm/modules/mailpoet/admin/mailpoet-hub/main.page.php @@ -1,5 +1,5 @@ -' . __( 'This will restart syncing your MailPoet subscribers from scratch, using your current settings.', 'zero-bs-crm' ) . '

'; + $html = '

' . __( 'This will restart syncing your MailPoet subscribers from scratch, using your current settings.', 'zero-bs-crm' ) . '

'; $html .= '

' . __( 'This will not remove any existing subscribers or data, but it will update objects if they are reimported and have since changed.', 'zero-bs-crm' ) . '

'; $html .= '

' . __( 'Yes, do a full resync', 'zero-bs-crm' ) . '  ' . __( 'No, cancel and go back to hub', 'zero-bs-crm' ) . '

'; @@ -47,30 +47,30 @@ function jpcrm_mailpoet_render_hub_page() { } // intercept for debug, if we have $_GET['debug_sync'], call that - if ( isset( $_GET['debug_sync'] ) ){ - + if ( isset( $_GET['debug_sync'] ) ) { + // render debug mode sync page jpcrm_mailpoet_render_hub_page_debug_mode(); exit( 0 ); } - $settings = $zbs->modules->mailpoet->settings->getAll(); + $settings = $zbs->modules->mailpoet->settings->getAll(); $settings_page_url = jpcrm_esc_link( $zbs->slugs['settings'] . '&tab=' . $zbs->modules->mailpoet->slugs['settings'] ); // retrieve current counts $jpcrm_mailpoet_latest_stats = $zbs->modules->mailpoet->get_jpcrm_mailpoet_latest_stats(); // various states: - if ( !$zbs->mailpoet_is_active() ){ + if ( ! $zbs->mailpoet_is_active() ) { - $error_notices[] = zeroBSCRM_UI2_messageHTML( 'warning', '', __( 'You do not currently have the MailPoet plugin installed. You\'ll need to install MailPoet to use MailPoet Sync', 'zero-bs-crm' ) ) ; + $error_notices[] = zeroBSCRM_UI2_messageHTML( 'warning', '', __( 'You do not currently have the MailPoet plugin installed. You\'ll need to install MailPoet to use MailPoet Sync', 'zero-bs-crm' ) ); $no_mailpoet_found = true; } // shorthand - $settings_cog_html = ''; + $settings_cog_html = ''; $settings_cog_button_html = '' . __( 'MailPoet Sync Settings', 'zero-bs-crm' ) . ''; ?> @@ -83,12 +83,14 @@ function jpcrm_mailpoet_render_hub_page() { 0 ){ + if ( count( $general_notices ) > 0 ) { ?>
- + } + ?>
- +

@@ -130,11 +134,12 @@ function jpcrm_mailpoet_render_hub_page() {

- + // Has plugin + ?>

@@ -146,7 +151,7 @@ function jpcrm_mailpoet_render_hub_page() {
' . esc_html( $jpcrm_mailpoet_latest_stats['subscribers_synced'] ) . ' ' . esc_html__( 'Subscribers Synced', 'zero-bs-crm' ); ?> - +


@@ -186,11 +191,14 @@ function jpcrm_mailpoet_render_hub_page() {
+ + modules->mailpoet->settings->getAll(); - $delete_action_options = array( - 'delete' => __( 'Delete CRM contact and associated objects', 'zero-bs-crm' ), - 'delete_save_related_objects' => __( 'Delete CRM contact but leave associated objects', 'zero-bs-crm' ), - 'add_note' => __( 'Add a note to the CRM contact', 'zero-bs-crm' ), - 'none' => __( 'No action', 'zero-bs-crm' ), - ); + $delete_action_options = array( + 'delete' => __( 'Delete CRM contact and associated objects', 'zero-bs-crm' ), + 'delete_save_related_objects' => __( 'Delete CRM contact but leave associated objects', 'zero-bs-crm' ), + 'add_note' => __( 'Add a note to the CRM contact', 'zero-bs-crm' ), + 'none' => __( 'No action', 'zero-bs-crm' ), + ); // Act on any edits! - if (isset($_POST['editwplf'])){ + if ( isset( $_POST['editwplf'] ) ) { // Retrieve $updatedSettings = array(); // tag object settings - $updatedSettings['tag_with_list'] = ( isset( $_POST['jpcrm_tag_with_list'] ) && !empty( $_POST['jpcrm_tag_with_list'] ) ? 1 : 0 ); - $updatedSettings['tag_with_tags'] = ( isset( $_POST['jpcrm_tag_with_tags'] ) && !empty( $_POST['jpcrm_tag_with_tags'] ) ? 1 : 0 ); + $updatedSettings['tag_with_list'] = ( isset( $_POST['jpcrm_tag_with_list'] ) && ! empty( $_POST['jpcrm_tag_with_list'] ) ? 1 : 0 ); + $updatedSettings['tag_with_tags'] = ( isset( $_POST['jpcrm_tag_with_tags'] ) && ! empty( $_POST['jpcrm_tag_with_tags'] ) ? 1 : 0 ); $updatedSettings['tag_list_prefix'] = ( isset( $_POST['jpcrm_tag_list_prefix'] ) ? jpcrm_sanitize_text_field_allow_whitespace( $_POST['jpcrm_tag_list_prefix'] ) : 'MailPoet List: ' ); - $updatedSettings['tag_tag_prefix'] = ( isset( $_POST['jpcrm_tag_tag_prefix'] ) ? jpcrm_sanitize_text_field_allow_whitespace( $_POST['jpcrm_tag_tag_prefix'] ) : 'MailPoet Tag: ' ); + $updatedSettings['tag_tag_prefix'] = ( isset( $_POST['jpcrm_tag_tag_prefix'] ) ? jpcrm_sanitize_text_field_allow_whitespace( $_POST['jpcrm_tag_tag_prefix'] ) : 'MailPoet Tag: ' ); - // autolog changes - $updatedSettings['autolog_changes'] = ( isset( $_POST['jpcrm_autolog_changes'] ) && !empty( $_POST['jpcrm_autolog_changes'] ) ? 1 : 0 ); + // autolog changes + $updatedSettings['autolog_changes'] = ( isset( $_POST['jpcrm_autolog_changes'] ) && ! empty( $_POST['jpcrm_autolog_changes'] ) ? 1 : 0 ); - // delete action - $updatedSettings['delete_action'] = ( isset( $_POST['jpcrm_delete_action'] ) && in_array( $_POST['jpcrm_delete_action'], array_keys( $delete_action_options ) ) ? sanitize_text_field( $_POST['jpcrm_delete_action'] ) : 'none' ); + // delete action + $updatedSettings['delete_action'] = ( isset( $_POST['jpcrm_delete_action'] ) && in_array( $_POST['jpcrm_delete_action'], array_keys( $delete_action_options ) ) ? sanitize_text_field( $_POST['jpcrm_delete_action'] ) : 'none' ); #} Brutal update - foreach ($updatedSettings as $k => $v){ - $zbs->modules->mailpoet->settings->update($k,$v); + foreach ( $updatedSettings as $k => $v ) { + $zbs->modules->mailpoet->settings->update( $k, $v ); } // $msg out! @@ -62,86 +62,121 @@ function jpcrm_settings_page_html_mailpoet_main(){ jpcrm_render_setting_title( 'MailPoet Sync Settings', '' ); ?> -

+

%s', jpcrm_esc_link( $zbs->slugs['mailpoet'] ), esc_html__( 'MailPoet Sync Hub', 'zero-bs-crm' ) - ); ?> -

-

+ ); + ?> +

+

- '. esc_html__( 'Settings Updated', 'zero-bs-crm' ) . ''; } ?> - -
-
- -

' . $zbs_biz_name . '
' . $zbs_biz_yourname . '
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ' . esc_html__( 'Settings Updated', 'zero-bs-crm' ) . ''; } + } + ?> - -
:

/>

" />

/>

" />

/>

- -
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
:

+ />

" />

+ />

" />

+ />

+ +
diff --git a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-admin-integration.php b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-admin-integration.php index fc782c925e1e..2f52f75e7b31 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-admin-integration.php +++ b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-admin-integration.php @@ -1,5 +1,5 @@ init_hooks(); - } - /** * Main Class Instance. @@ -40,17 +37,16 @@ public function __construct() { * * @since 2.0 * @static - * @see + * @see * @return Mailpoet_Admin_Integration main instance */ public static function instance() { - if ( is_null( self::$_instance ) ) { + if ( self::$_instance === null ) { self::$_instance = new self(); } return self::$_instance; } - /** * Initialise Hooks */ @@ -61,6 +57,5 @@ private function init_hooks() { // Add button column to subscriber list page 'View CRM Contact' // /wp-admin/admin.php?page=mailpoet-subscribers#/ - } } diff --git a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-background-sync-job.php b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-background-sync-job.php index 7f325b906456..7c69576e9db5 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-background-sync-job.php +++ b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-background-sync-job.php @@ -1,5 +1,5 @@ -debug = $debug; + $this->debug = $debug; $this->subscribers_per_page = $subscribers_per_page; - $this->pages_per_job = $pages_per_job; + $this->pages_per_job = $pages_per_job; // promote paused state // - } - /** * Returns main class instance */ - public function mailpoet(){ + public function mailpoet() { global $zbs; return $zbs->modules->mailpoet; - } - /** * Returns full settings array from main settings class */ - public function settings(){ + public function settings() { return $this->mailpoet()->settings->getAll(); - } - /** * If $this->debug is true, outputs passed string * * @param string - Debug string */ - private function debug( $str ){ + private function debug( $str ) { - if ( $this->debug ){ + if ( $this->debug ) { echo '[' . zeroBSCRM_locale_utsToDatetime( time() ) . '] ' . $str . '
'; } - } - /** * Main job function: this will retrieve and import subscribers from MailPoet into CRM. - * + * * @return mixed (int|json) * - if cron originated: a count of subscribers imported is returned * - if not cron originated (assumes AJAX): * - if completed sync: JSON summary info is output and then exit() is called * - else count of subscribers imported is returned */ - public function run_sync(){ + public function run_sync() { global $zbs; $this->debug( 'Fired `run_sync()`' ); // prep vars - $run_sync_job = true; + $run_sync_job = true; $total_remaining_pages = 0; - $total_pages = 0; - $errors = array(); - $subscribers_synced = 0; + $total_pages = 0; + $errors = array(); + $subscribers_synced = 0; // check not marked 'paused' - if ( $this->paused ){ + if ( $this->paused ) { // skip it $this->debug( 'Skipping Sync (mode: ' . $this->mode . ') - Paused' ); @@ -146,11 +137,11 @@ public function run_sync(){ // switch by mode if ( $this->mode == JPCRM_MAILPOET_MODE_LOCAL ) { - + // local install // verify mailpoet installed - if ( !$zbs->mailpoet_is_active() ) { + if ( ! $zbs->mailpoet_is_active() ) { $status_short_text = __( 'Missing MailPoet', 'zero-bs-crm' ); @@ -167,7 +158,6 @@ public function run_sync(){ $run_sync_job = false; } - } else { // no mode, or a faulty one! @@ -185,7 +175,7 @@ public function run_sync(){ } - if ( $run_sync_job ){ + if ( $run_sync_job ) { $this->debug( 'Running Import of ' . $this->pages_per_job . ' pages' ); @@ -207,8 +197,8 @@ public function run_sync(){ // import the page of subscribers // This always returns the count of imported subscribers, - // unless 100% sync is reached, at which point it will exit (if called via AJAX) - // for now, we don't need to track the return + // unless 100% sync is reached, at which point it will exit (if called via AJAX) + // for now, we don't need to track the return $subscribers_synced += (int) $this->import_page_of_subscribers( $page_to_retrieve ); $this->debug( 'Subscribers completed: ' . min( ( $this->current_page * $this->subscribers_per_page ) + $subscribers_synced, $this->mailpoet_total_subscribers ) . ' / ' . $this->mailpoet_total_subscribers ); @@ -223,13 +213,13 @@ public function run_sync(){ // return overall % counts later used to provide a summary % across sync site connections $percentage_counts = $this->percentage_completed( true ); if ( is_array( $percentage_counts ) ) { - $total_pages = (int)$percentage_counts['total_pages']; + $total_pages = (int) $percentage_counts['total_pages']; $total_remaining_pages = $percentage_counts['total_pages'] - ( $percentage_counts['page_no'] + 1 ); } // We should never have less than zero here // (seems to happen when site connections error out) - if ( $total_remaining_pages < 0 ){ + if ( $total_remaining_pages < 0 ) { $total_remaining_pages = 0; } @@ -237,12 +227,10 @@ public function run_sync(){ 'total_pages' => $total_pages, 'total_remaining_pages' => $total_remaining_pages, 'errors' => $errors, - 'subscribers_synced' => $subscribers_synced + 'subscribers_synced' => $subscribers_synced, ); - } - /** * Retrieve and process 1 page of MailPoet Subscribers from local install (or later, API) * @@ -270,10 +258,8 @@ private function import_page_of_subscribers( $page_no ) { return false; } - } - /** * Retrieve and process a page of MailPoet Subscribers from local install * @@ -290,7 +276,7 @@ public function import_local_subscribers( $page_no = -1 ) { // Where we're trying to run without MailPoet, fail. // In theory we shouldn't ever hit this, as we catch it earlier. global $zbs; - if ( !$zbs->mailpoet_is_active() ) { + if ( ! $zbs->mailpoet_is_active() ) { $this->debug( 'Unable to import as it appears the MailPoet plugin is not installed.' ); return false; } @@ -299,7 +285,7 @@ public function import_local_subscribers( $page_no = -1 ) { if ( $page_no < 0 ) { $page_no = 0; } - $limit = $this->subscribers_per_page; + $limit = $this->subscribers_per_page; $offset = $this->subscribers_per_page * $page_no; $this->debug( 'Retrieving page ' . $page_no . ' of subscribers (limit=' . $limit . ', offset=' . $offset . ')' ); @@ -318,10 +304,9 @@ public function import_local_subscribers( $page_no = -1 ) { // will be an assoc arr of sub details $this->import_subscriber( $subscriber ); - $subscribers_synced++; + ++$subscribers_synced; } - } else { $this->debug( 'No MailPoet subscribers found (have we reached the end of the list?)' ); @@ -361,7 +346,7 @@ public function import_local_subscribers( $page_no = -1 ) { * Takes a MailPoet associative array for a subscriber and adds/updates a crm contact * * @param array $subscriber - * + * * @return int $contact_id */ public function import_subscriber( $subscriber ) { @@ -373,39 +358,39 @@ public function import_subscriber( $subscriber ) { // get wpid where passed $wpid = -1; - if ( isset( $subscriber['wp_user_id'] ) && !empty( $subscriber['wp_user_id'] ) ){ + if ( isset( $subscriber['wp_user_id'] ) && ! empty( $subscriber['wp_user_id'] ) ) { $wpid = $subscriber['wp_user_id']; } // unused subscriber attributes: - // is_woocommerce_user, status, subscribed_ip, confirmed_ip, confirmed_at, last_subscribed_at, - // updated_at, deleted_at, unconfirmed_data, source (e.g. wordpress user), count_confirmations, + // is_woocommerce_user, status, subscribed_ip, confirmed_ip, confirmed_at, last_subscribed_at, + // updated_at, deleted_at, unconfirmed_data, source (e.g. WordPress user), count_confirmations, // unsubscribe_token, link_token, engagement_score, engagement_score_updated_at, last_engagement_at // woocommerce_synced_at, email_count $contact_args = array( 'data' => array( - 'email' => $subscriber['email'], - 'fname' => $subscriber['first_name'], - 'lname' => $subscriber['last_name'], - 'wpid' => $wpid, + 'email' => $subscriber['email'], + 'fname' => $subscriber['first_name'], + 'lname' => $subscriber['last_name'], + 'wpid' => $wpid, - 'externalSources' => array( - array( - 'source' => 'mailpoet', - 'uid' => $subscriber['id'], - 'origin' => '', // for now this is always same-site - 'owner' => 0 // for now we hard-type no owner to avoid ownership issues. As we roll out fuller ownership we may want to adapt this. - ) - ), + 'externalSources' => array( + array( + 'source' => 'mailpoet', + 'uid' => $subscriber['id'], + 'origin' => '', // for now this is always same-site + 'owner' => 0, // for now we hard-type no owner to avoid ownership issues. As we roll out fuller ownership we may want to adapt this. + ), + ), - 'created' => strtotime( $subscriber['created_at'] ), + 'created' => strtotime( $subscriber['created_at'] ), ), - //'extraMeta' => array() + // 'extraMeta' => array() ); @@ -447,7 +432,6 @@ public function import_subscriber( $subscriber ) { } } } - } if ( $settings['tag_with_tags'] == 1 ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual @@ -475,19 +459,17 @@ public function import_subscriber( $subscriber ) { } } } - } // got tags? - if ( count( $tags ) > 0 ){ + if ( count( $tags ) > 0 ) { - $contact_args['data']['tags'] = $tags; + $contact_args['data']['tags'] = $tags; $contact_args['data']['tag_mode'] = 'append'; } - - //$this->debug( 'Add/Update contact:
' . var_export( $contact_args ) . '
' ); + // $this->debug( 'Add/Update contact:
' . var_export( $contact_args ) . '
' ); // Add/update the contact & return id return $zbs->DAL->contacts->addUpdateContact( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase @@ -498,18 +480,17 @@ public function import_subscriber( $subscriber ) { ); } - /** * Returns a number for total pages to process (with current $this->subscribers_per_page) * * @return int $total_pages */ - public function get_total_page_count(){ + public function get_total_page_count() { // calculate it $this->mailpoet_total_subscribers = $this->mailpoet()->get_all_mailpoet_subscribers_count(); - $total_pages = 0; - if ( $this->subscribers_per_page > 0 && $this->mailpoet_total_subscribers > 0 ){ + $total_pages = 0; + if ( $this->subscribers_per_page > 0 && $this->mailpoet_total_subscribers > 0 ) { $total_pages = ceil( $this->mailpoet_total_subscribers / $this->subscribers_per_page ); @@ -518,10 +499,8 @@ public function get_total_page_count(){ $this->mailpoet_total_pages = $total_pages; return $total_pages; - } - /** * Set's a completion status for subscriber imports * (Wrapper) @@ -530,60 +509,52 @@ public function get_total_page_count(){ * * @return bool $status */ - public function set_first_import_status( $status ){ + public function set_first_import_status( $status ) { return $this->mailpoet()->background_sync->set_first_import_status( $status ); - } - /** * Returns a completion status for subscriber imports * (Wrapper) - * + * * @return bool $status */ - public function first_import_completed(){ + public function first_import_completed() { return $this->mailpoet()->background_sync->first_import_completed(); - } /** * Sets current working page index (to resume from) * (Wrapper) - * + * * @return int $page */ - public function set_resume_from_page( $page_no ){ + public function set_resume_from_page( $page_no ) { return $this->mailpoet()->background_sync->set_resume_from_page( $page_no ); - } - /** * Return current working page index (to resume from) * (Wrapper) - * + * * @return int $page */ - public function resume_from_page(){ + public function resume_from_page() { return $this->mailpoet()->background_sync->resume_from_page(); - } - /** * Returns 'local' or 'api' * (whichever mode is selected in settings) * (Wrapper) */ - public function import_mode( $str_mode = false ){ + public function import_mode( $str_mode = false ) { return $this->mailpoet()->background_sync->import_mode( $str_mode ); - } /** @@ -591,13 +562,13 @@ public function import_mode( $str_mode = false ){ * * @param bool $return_counts - Return counts (if true returns an array inc % completed, x of y pages) * @param bool $use_cache - use values cached in object instead of retrieving them directly from MailPoet - * + * * @return int|bool - percentage completed, or false if not attainable */ public function percentage_completed( $return_counts = false, $use_cache = true ) { // if not using cache, retrieve values from MailPoet - if ( !$use_cache ) { + if ( ! $use_cache ) { // could probably abstract the retrieval of subscribers for more nesting. For now it's fairly DRY as only in 2 places. @@ -619,12 +590,12 @@ public function percentage_completed( $return_counts = false, $use_cache = true $this->debug( 'Percentage completed: ' . $percentage_completed . '%' ); $this->debug( 'Pages completed: ' . ( $this->current_page + 1 ) . ' / ' . $this->mailpoet_total_pages ); - if ( $return_counts ){ + if ( $return_counts ) { return array( 'page_no' => $this->current_page, 'total_pages' => $this->mailpoet_total_pages, - 'percentage_completed' => $percentage_completed + 'percentage_completed' => $percentage_completed, ); } @@ -637,6 +608,5 @@ public function percentage_completed( $return_counts = false, $use_cache = true } return false; - } } diff --git a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-background-sync.php b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-background-sync.php index 9a27c7e248aa..61a1f67e443b 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-background-sync.php +++ b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-background-sync.php @@ -1,5 +1,5 @@ init_hooks(); // Schedule cron $this->schedule_cron(); - } - /** * Main Class Instance. @@ -55,44 +53,39 @@ public function __construct() { * * @since 2.0 * @static - * @see + * @see * @return Mailpoet_Background_Sync main instance */ public static function instance() { - if ( is_null( self::$_instance ) ) { + if ( self::$_instance === null ) { self::$_instance = new self(); } return self::$_instance; } - /** * Returns main class instance */ - public function mailpoet(){ + public function mailpoet() { global $zbs; return $zbs->modules->mailpoet; - } - /** * If $this->debug is true, outputs passed string * * @param string - Debug string */ - private function debug( $str ){ + private function debug( $str ) { - if ( $this->debug ){ + if ( $this->debug ) { echo '[' . zeroBSCRM_locale_utsToDatetime( time() ) . '] ' . $str . '
'; } - } - /** * Initialise Hooks */ @@ -104,19 +97,17 @@ private function init_hooks() { // Syncing based on MailPoet hooks: // Subscriber edits/changes: - add_action( 'mailpoet_subscriber_created', array( $this, 'add_update_subscriber_by_id' ), 1, 1 ); - add_action( 'mailpoet_subscriber_updated', array( $this, 'add_update_subscriber_by_id' ), 1, 1 ); - add_action( 'mailpoet_subscriber_deleted', array( $this, 'delete_subscriber_by_id' ), 1, 1 ); - add_action( 'mailpoet_multiple_subscribers_created', array( $this, 'add_update_subscribers_by_id' ), 1, 1 ); - add_action( 'mailpoet_multiple_subscribers_updated', array( $this, 'add_update_subscribers_by_id' ), 1, 1 ); - add_action( 'mailpoet_multiple_subscribers_deleted', array( $this, 'delete_subscribers_by_id' ), 1, 1 ); + add_action( 'mailpoet_subscriber_created', array( $this, 'add_update_subscriber_by_id' ), 1, 1 ); + add_action( 'mailpoet_subscriber_updated', array( $this, 'add_update_subscriber_by_id' ), 1, 1 ); + add_action( 'mailpoet_subscriber_deleted', array( $this, 'delete_subscriber_by_id' ), 1, 1 ); + add_action( 'mailpoet_multiple_subscribers_created', array( $this, 'add_update_subscribers_by_id' ), 1, 1 ); + add_action( 'mailpoet_multiple_subscribers_updated', array( $this, 'add_update_subscribers_by_id' ), 1, 1 ); + add_action( 'mailpoet_multiple_subscribers_deleted', array( $this, 'delete_subscribers_by_id' ), 1, 1 ); // add our cron task to the core crm cron monitor list - add_filter( 'jpcrm_cron_to_monitor', array( $this, 'add_cron_monitor' ) ); - + add_filter( 'jpcrm_cron_to_monitor', array( $this, 'add_cron_monitor' ) ); } - /** * Setup cron schedule */ @@ -124,35 +115,30 @@ private function schedule_cron() { // schedule it if ( ! wp_next_scheduled( 'jpcrm_mailpoet_sync' ) ) { - wp_schedule_event( time(), '5min', 'jpcrm_mailpoet_sync' ); - } - + wp_schedule_event( time(), '5min', 'jpcrm_mailpoet_sync' ); + } } - /** * Run cron job */ - public function cron_job(){ + public function cron_job() { // define global to mark this as a cron call define( 'jpcrm_mailpoet_cron_running', 1 ); // fire job $this->sync_subscribers(); - } /** * Returns bool as to whether or not the current call was made via cron */ - private function is_cron(){ + private function is_cron() { return defined( 'jpcrm_mailpoet_cron_running' ); - } - /** * Filter call to add the cron zbssendbot to the watcher system * @@ -163,16 +149,15 @@ function add_cron_monitor( $crons ) { if ( is_array( $crons ) ) { - $crons[ 'jpcrm_mailpoet_sync' ] = '5min'; + $crons['jpcrm_mailpoet_sync'] = '5min'; } return $crons; } - /** * Main job function: this will retrieve and import subscribers from MailPoet - * This can be called in three 'modes' + * This can be called in three 'modes' * - via cron (as defined by `jpcrm_mailpoet_cron_running`) * - via AJAX (if not via cron and not in debug mode) * - for debug (if $this->debug is set) This is designed to be called inline and will output progress of sync job @@ -185,10 +170,9 @@ function add_cron_monitor( $crons ) { * - if completed sync: JSON summary info is output and then exit() is called * - else count of subscribers imported is returned */ - public function sync_subscribers( $silent = false ){ + public function sync_subscribers( $silent = false ) { global $zbs; - $this->debug( 'Fired `sync_subscribers()`.' ); @@ -206,15 +190,15 @@ public function sync_subscribers( $silent = false ){ // prep silos $total_remaining_pages = 0; - $total_pages = 0; - $errors = array(); - $subscribers_synced = 0; + $total_pages = 0; + $errors = array(); + $subscribers_synced = 0; + + // blocker + if ( ! defined( 'jpcrm_mailpoet_running' ) ) { - // blocker - if ( !defined( 'jpcrm_mailpoet_running' ) ) { - define( 'jpcrm_mailpoet_running', 1 ); - + } // init class @@ -222,10 +206,11 @@ public function sync_subscribers( $silent = false ){ // start sync job $sync_result = $sync_job->run_sync(); - + $this->debug( 'Sync Result:
' . print_r( $sync_result, 1 ) . '
' ); - /* will be + /* + will be false or @@ -238,31 +223,30 @@ public function sync_subscribers( $silent = false ){ );*/ - if ( is_array( $sync_result ) && isset( $sync_result['total_pages'] ) && isset( $sync_result['total_remaining_pages'] ) ){ + if ( is_array( $sync_result ) && isset( $sync_result['total_pages'] ) && isset( $sync_result['total_remaining_pages'] ) ) { // maintain overall % counts later used to provide a summary % across sync site connections - $total_pages += (int)$sync_result['total_pages']; + $total_pages += (int) $sync_result['total_pages']; $total_remaining_pages += $sync_result['total_remaining_pages']; - $subscribers_synced = (int)$sync_result['subscribers_synced']; + $subscribers_synced = (int) $sync_result['subscribers_synced']; } - // discern completeness // either maxxed pages, or more likely x no = y no - if ( $total_remaining_pages == 0 || $this->mailpoet()->get_all_mailpoet_subscribers_count() <= $this->mailpoet()->get_crm_mailpoet_contact_count() ){ + if ( $total_remaining_pages == 0 || $this->mailpoet()->get_all_mailpoet_subscribers_count() <= $this->mailpoet()->get_crm_mailpoet_contact_count() ) { - $sync_status = 'sync_completed'; + $sync_status = 'sync_completed'; $overall_percentage = 100; - $status_short_text = __( 'Sync Completed', 'zero-bs-crm' ); - $status_long_text = __( 'MailPoet Sync has imported all existing subscribers and will continue to import future subscribers.', 'zero-bs-crm' ); + $status_short_text = __( 'Sync Completed', 'zero-bs-crm' ); + $status_long_text = __( 'MailPoet Sync has imported all existing subscribers and will continue to import future subscribers.', 'zero-bs-crm' ); } else { - $sync_status = 'sync_part_complete'; - $overall_percentage = (int)( ( $total_pages - $total_remaining_pages ) / $total_pages * 100 ); - $status_short_text = __( 'Syncing subscribers from MailPoet...', 'zero-bs-crm' ); - $status_long_text = ''; + $sync_status = 'sync_part_complete'; + $overall_percentage = (int) ( ( $total_pages - $total_remaining_pages ) / $total_pages * 100 ); + $status_short_text = __( 'Syncing subscribers from MailPoet...', 'zero-bs-crm' ); + $status_long_text = ''; } @@ -271,9 +255,9 @@ public function sync_subscribers( $silent = false ){ return array( - 'status' => $sync_status, // sync_completed sync_part_complete job_in_progress error - 'status_short_text' => $status_short_text, - 'percentage_completed' => $overall_percentage, + 'status' => $sync_status, // sync_completed sync_part_complete job_in_progress error + 'status_short_text' => $status_short_text, + 'percentage_completed' => $overall_percentage, ); @@ -287,15 +271,13 @@ public function sync_subscribers( $silent = false ){ 'page_no' => ( $total_pages - $total_remaining_pages ), 'subscribers_synced' => $subscribers_synced, 'percentage_completed' => $overall_percentage, - 'total_crm_contacts_from_mailpoet' => $this->mailpoet()->get_crm_mailpoet_contact_count() + 'total_crm_contacts_from_mailpoet' => $this->mailpoet()->get_crm_mailpoet_contact_count(), ); - $mailpoet_latest_stats = $this->mailpoet()->get_jpcrm_mailpoet_latest_stats(); + $mailpoet_latest_stats = $this->mailpoet()->get_jpcrm_mailpoet_latest_stats(); wp_send_json( array_merge( $mailpoet_latest_stats, $mailpoetsync_status_array ) ); } - } - /** * Set's a completion status for MailPoet Subscriber imports * @@ -303,44 +285,41 @@ public function sync_subscribers( $silent = false ){ * * @return bool $status */ - public function set_first_import_status( $status ){ + public function set_first_import_status( $status ) { $status_bool = false; - if ( $status == 'yes' || $status === true ){ + if ( $status == 'yes' || $status === true ) { $status_bool = true; } - // set it + // set it $this->mailpoet()->settings->update( 'first_import_complete', $status_bool ); return $status_bool; - } - /** * Returns a completion status for MailPoet Subscriber imports * * @return bool $status */ - public function first_import_completed(){ + public function first_import_completed() { $status_bool = false; // get $first_import_complete = $this->mailpoet()->settings->get( 'first_import_complete', false ); - if ( $first_import_complete == 'yes' || $first_import_complete === true || $first_import_complete == 1 ){ + if ( $first_import_complete == 'yes' || $first_import_complete === true || $first_import_complete == 1 ) { $status_bool = true; } return $status_bool; - } /** @@ -348,35 +327,31 @@ public function first_import_completed(){ * * @return int $page */ - public function set_resume_from_page( $page_no ){ + public function set_resume_from_page( $page_no ) { $this->mailpoet()->settings->update( 'resume_from_page', $page_no ); return $page_no; - } - /** * Return current working page index (to resume from) * * @return int $page */ - public function resume_from_page(){ + public function resume_from_page() { return $this->mailpoet()->settings->get( 'resume_from_page', 0 ); - } - /** * Returns 'local' or 'api' * (whichever mode is selected in settings) */ - public function import_mode( $str_mode = false ){ + public function import_mode( $str_mode = false ) { // import mode - $mode = (int)$this->mode; + $mode = (int) $this->mode; // debug/string mode if ( $str_mode ) { @@ -388,11 +363,8 @@ public function import_mode( $str_mode = false ){ } return $mode; - } - - /** * Add or Update subscriber * Fired by hooks: mailpoet_subscriber_created, mailpoet_subscriber_updated, mailpoet_subscriber_deleted @@ -401,7 +373,7 @@ public function import_mode( $str_mode = false ){ * - email * - doens't seem to fire on: change of newsletter, change of tags */ - public function add_update_subscriber_by_id( int $subscriberId ){ + public function add_update_subscriber_by_id( int $subscriberId ) { global $zbs; @@ -410,134 +382,135 @@ public function add_update_subscriber_by_id( int $subscriberId ){ // retrieve records $potential_subscriber = $this->mailpoet()->get_mailpoet_subscriber_by_subscriber_id( $subscriberId ); - $potential_contact = $zbs->DAL->contacts->getContact( -1, array( + $potential_contact = $zbs->DAL->contacts->getContact( + -1, + array( - 'externalSource' => 'mailpoet', - 'externalSourceUID' => $subscriberId, + 'externalSource' => 'mailpoet', + 'externalSourceUID' => $subscriberId, - )); + ) + ); // got records? if ( is_array( $potential_subscriber ) && isset( $potential_subscriber['email'] ) - ){ + ) { // Update: - if ( is_array( $potential_contact ) && isset( $potential_contact['id'] ) ){ - + if ( is_array( $potential_contact ) && isset( $potential_contact['id'] ) ) { + // note changes - $previous_data = $potential_contact; + $previous_data = $potential_contact; $contact_changes = array(); // email (will always be the same until https://github.com/Automattic/zero-bs-crm/issues/2565) // ... in fact this next block is defunct as it stands because getSubscriber above gets the subscriber // ... AFTER email change. - if ( $potential_subscriber['email'] != $potential_contact['email'] ){ + if ( $potential_subscriber['email'] != $potential_contact['email'] ) { $contact_changes['email'] = $potential_subscriber->data->email; // if email changed, add old as an alias // for that we need the old alias list to append to $contact_aliases = is_array( $potential_contact['aliases'] ) ? $potential_contact['aliases'] : array(); - if ( !in_array( $previous_data['email'], $contact_aliases ) ){ + if ( ! in_array( $previous_data['email'], $contact_aliases ) ) { $contact_aliases[] = $previous_data['email']; } - } // first name - if ( $potential_subscriber['first_name'] != $potential_contact['fname'] ){ + if ( $potential_subscriber['first_name'] != $potential_contact['fname'] ) { $contact_changes['fname'] = $potential_subscriber['first_name']; } // last name - if ( $potential_subscriber['last_name'] != $potential_contact['lname'] ){ + if ( $potential_subscriber['last_name'] != $potential_contact['lname'] ) { $contact_changes['lname'] = $potential_subscriber['last_name']; - } + } // enact changes - if ( count( $contact_changes ) > 0 ){ - + if ( count( $contact_changes ) > 0 ) { + // we split this into field + contact_aliases changes, because then we can use limitedFields support // build limited fields: $contact_changes_as_limited_fields = array(); - foreach ( $contact_changes as $key => $value ){ + foreach ( $contact_changes as $key => $value ) { $contact_changes_as_limited_fields[] = array( - 'key' => 'zbsc_' . $key, - 'val' => $value, - 'type' => '%s' // all are strings here + 'key' => 'zbsc_' . $key, + 'val' => $value, + 'type' => '%s', // all are strings here ); } // enact - $zbs->DAL->contacts->addUpdateContact( array( - - 'id' => $potential_contact['id'], - 'limitedFields' => $contact_changes_as_limited_fields + $zbs->DAL->contacts->addUpdateContact( + array( - )); + 'id' => $potential_contact['id'], + 'limitedFields' => $contact_changes_as_limited_fields, + + ) + ); // any aliases to add? - if ( isset( $contact_aliases ) && count( $contact_aliases ) ){ + if ( isset( $contact_aliases ) && count( $contact_aliases ) ) { - foreach ( $contact_aliases as $alias ){ + foreach ( $contact_aliases as $alias ) { - zeroBS_addObjAlias( ZBS_TYPE_CONTACT, $potential_contact['id'], $alias ); + zeroBS_addObjAlias( ZBS_TYPE_CONTACT, $potential_contact['id'], $alias ); } - } // do we add logs? - if ( $autolog_changes == "1" ){ + if ( $autolog_changes == '1' ) { // build log $object_change_str = ''; - if ( isset( $contact_changes['email'] ) ){ + if ( isset( $contact_changes['email'] ) ) { - $object_change_str .= sprintf ( '%s: %s%s
', __( 'Email', 'zero-bs-crm' ), $previous_data['email'], $contact_changes['email'] ); + $object_change_str .= sprintf( '%s: %s%s
', __( 'Email', 'zero-bs-crm' ), $previous_data['email'], $contact_changes['email'] ); } - if ( isset( $contact_changes['fname'] ) ){ + if ( isset( $contact_changes['fname'] ) ) { - $object_change_str .= sprintf ( '%s: %s%s
', __( 'First name', 'zero-bs-crm' ), $previous_data['fname'], $contact_changes['fname'] ); + $object_change_str .= sprintf( '%s: %s%s
', __( 'First name', 'zero-bs-crm' ), $previous_data['fname'], $contact_changes['fname'] ); } - if ( isset( $contact_changes['lname'] ) ){ + if ( isset( $contact_changes['lname'] ) ) { - $object_change_str .= sprintf ( '%s: %s%s
', __( 'Last name', 'zero-bs-crm' ), $previous_data['lname'], $contact_changes['lname'] ); + $object_change_str .= sprintf( '%s: %s%s
', __( 'Last name', 'zero-bs-crm' ), $previous_data['lname'], $contact_changes['lname'] ); } // add log - if ( !empty( $object_change_str ) ){ + if ( ! empty( $object_change_str ) ) { zeroBS_addUpdateLog( $potential_contact['id'], -1, -1, array( - 'type' => __( 'Contact Changed via MailPoet', 'zero-bs-crm' ), + 'type' => __( 'Contact Changed via MailPoet', 'zero-bs-crm' ), 'shortdesc' => __( 'Contact details changed via connected MailPoet subscriber', 'zero-bs-crm' ), - 'longdesc' => $object_change_str, + 'longdesc' => $object_change_str, ), 'zerobs_customer' ); } - } - } return; @@ -546,7 +519,7 @@ public function add_update_subscriber_by_id( int $subscriberId ){ // New addition - // Note we can't act on this hook because currently the only thing passed is the + // Note we can't act on this hook because currently the only thing passed is the // MailPoet ID, from which the user can't currently (via MailPoet API) be retrieved // ... so when they add that we can use $this->mailpoet()->get_mailpoet_subscriber_by_subscriber_id // in it's real sense and write logic here to import the addition. @@ -555,9 +528,7 @@ public function add_update_subscriber_by_id( int $subscriberId ){ // see #temporary-workaround // gh-2565 - } - } // Temporary workaround for lack of accessibility to getSubscriberByID in MP API @@ -566,9 +537,9 @@ public function add_update_subscriber_by_id( int $subscriberId ){ // Attempts to grab the last inserted sub. This will be hit and miss, but will work smoothly for // small, infrequently updated lists $last_updated_guess_timestamp = time() + jpcrm_get_wp_timezone_offset_in_seconds() - 1; - $potential_subscribers = $this->mailpoet()->get_mailpoet_subscribers( false, false, $last_updated_guess_timestamp, 1, 0, false, true, true ); + $potential_subscribers = $this->mailpoet()->get_mailpoet_subscribers( false, false, $last_updated_guess_timestamp, 1, 0, false, true, true ); - if ( is_array( $potential_subscribers ) && count( $potential_subscribers ) > 0 ){ + if ( is_array( $potential_subscribers ) && count( $potential_subscribers ) > 0 ) { // push this sub through our sync import function: @@ -577,15 +548,13 @@ public function add_update_subscriber_by_id( int $subscriberId ){ $sync_job->import_subscriber( $potential_subscribers[0] ); } - - } /** * Delete subscriber * Fired by hooks: mailpoet_subscriber_created, mailpoet_subscriber_updated, mailpoet_subscriber_deleted */ - public function delete_subscriber_by_id( int $subscriberId ){ + public function delete_subscriber_by_id( int $subscriberId ) { global $zbs; @@ -593,54 +562,61 @@ public function delete_subscriber_by_id( int $subscriberId ){ $delete_action = $this->mailpoet()->settings->get( 'delete_action', 'none' ); // shall we delete the related crm contact? - if ( $delete_action == 'delete' || $delete_action == 'delete_save_related_objects' ){ + if ( $delete_action == 'delete' || $delete_action == 'delete_save_related_objects' ) { // retrieve record - $potential_contact_id = $zbs->DAL->contacts->getContact( -1, array( + $potential_contact_id = $zbs->DAL->contacts->getContact( + -1, + array( - 'externalSource' => 'mailpoet', - 'externalSourceUID' => $subscriberId, + 'externalSource' => 'mailpoet', + 'externalSourceUID' => $subscriberId, - 'onlyID' => true, + 'onlyID' => true, - )); + ) + ); // got record? - if ( $potential_contact_id ){ + if ( $potential_contact_id ) { $save_orphans = false; if ( $delete_action == 'delete_save_related_objects' ) { - + $save_orphans = true; } // delete the contact - $zbs->DAL->contacts->deleteContact( array( + $zbs->DAL->contacts->deleteContact( + array( - 'id' => $potential_contact_id, - 'saveOrphans' => $save_orphans, + 'id' => $potential_contact_id, + 'saveOrphans' => $save_orphans, - )); + ) + ); } - } elseif ( $delete_action == 'add_note' ) { // if it was deleted in MailPoet but user has 'add_note' selected as delete action, we add a log to contact // retrieve record - $potential_contact_id = $zbs->DAL->contacts->getContact( -1, array( + $potential_contact_id = $zbs->DAL->contacts->getContact( + -1, + array( - 'externalSource' => 'mailpoet', - 'externalSourceUID' => $subscriberId, + 'externalSource' => 'mailpoet', + 'externalSourceUID' => $subscriberId, - 'onlyID' => true, + 'onlyID' => true, - )); + ) + ); // got record? - if ( $potential_contact_id ){ + if ( $potential_contact_id ) { zeroBS_addUpdateLog( $potential_contact_id, @@ -649,50 +625,44 @@ public function delete_subscriber_by_id( int $subscriberId ){ array( 'type' => __( 'Subscriber deleted in MailPoet', 'zero-bs-crm' ), 'shortdesc' => __( 'Associated MailPoet subscriber was deleted in MailPoet', 'zero-bs-crm' ), - 'longdesc' => '' + 'longdesc' => '', ), 'zerobs_customer' ); } - } // if we're not deleting the contact, we need to remove the external source record // for the contact, because there's no link any more. // ... actually if we leave it in tact it still records useful info (the fact the source was MP) - } - /** - * Add or Update subscribers + * Add or Update subscribers * Fired by hooks: mailpoet_multiple_subscribers_created, mailpoet_multiple_subscribers_updated */ - public function add_update_subscribers_by_id( int $minActionTimestamp ){ + public function add_update_subscribers_by_id( int $minActionTimestamp ) { // catch these via sync $this->sync_subscribers( true ); - } - /** - * Delete subscribers + * Delete subscribers * Fired by hook: mailpoet_multiple_subscribers_deleted */ - public function delete_subscribers_by_id( array $subscriberIds ){ + public function delete_subscribers_by_id( array $subscriberIds ) { // here we rely on our other function `delete_subscriber_by_id()` // which has all of the settings-based delete actions - if ( count( $subscriberIds ) > 0 ){ + if ( count( $subscriberIds ) > 0 ) { - foreach ( $subscriberIds as $subscriber_id ){ + foreach ( $subscriberIds as $subscriber_id ) { $this->delete_subscriber_by_id( $subscriber_id ); - } + } } - } } diff --git a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-export-segment-to-mailpoet.php b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-export-segment-to-mailpoet.php index 9a7ab3da4718..70f60f26d8f9 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-export-segment-to-mailpoet.php +++ b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-export-segment-to-mailpoet.php @@ -1,5 +1,5 @@ init_hooks(); - } - /** * Main Class Instance. @@ -39,292 +36,309 @@ public function __construct() { * * @since 2.0 * @static - * @see + * @see * @return Mailpoet_Admin_Integration main instance */ public static function instance() { - if ( is_null( self::$_instance ) ) { + if ( self::$_instance === null ) { self::$_instance = new self(); } return self::$_instance; } - /** * Initialise Hooks */ private function init_hooks() { - add_action( 'jpcrm_segment_edit_export_mailpoet_button', function() { - // AJAX call to action 'jpcrm_segment_export_to_mailpoet' - ?> + add_action( + 'jpcrm_segment_edit_export_mailpoet_button', + function () { + // AJAX call to action 'jpcrm_segment_export_to_mailpoet' + ?> - $zbs->slugs['addedit'], 'zbstype' => 'segment' ) ) ){ + global $zbs, $pagenow; - $language_labels['mailpoet_list_exists'] = __( 'Previously Exported', 'zero-bs-crm' ); - $language_labels['mailpoet_list_exists_detail'] = __( 'This segment was previously exported to MailPoet. Are you sure you want to export it again?
(Doing so will overwrite the existing MailPoet List.)', 'zero-bs-crm' ); - $language_labels['continue_export'] = __( 'Start Export', 'zero-bs-crm' ); + // only on our page + if ( zeroBS_hasGETParamsWithValues( + array( 'admin.php' ), + array( + 'page' => $zbs->slugs['addedit'], + 'zbstype' => 'segment', + ) + ) ) { - } + $language_labels['mailpoet_list_exists'] = __( 'Previously Exported', 'zero-bs-crm' ); + $language_labels['mailpoet_list_exists_detail'] = __( 'This segment was previously exported to MailPoet. Are you sure you want to export it again?
(Doing so will overwrite the existing MailPoet List.)', 'zero-bs-crm' ); + $language_labels['continue_export'] = __( 'Start Export', 'zero-bs-crm' ); - return $language_labels; + } - }); + return $language_labels; + } + ); - add_action( 'segment_edit_extra_js', function() { - - // JS to initiate export when window param passed - ?> + add_action( + 'segment_edit_extra_js', + function () { - // Export segment as MailPoet list. - jQuery( '.zbs-segment-export-mailpoet' ).off( 'click' ).on( 'click', function ( e ) { - let exportButton = jQuery( e.target ); - jpcrm_segment_export_to_mailpoet( exportButton ); - }); + // JS to initiate export when window param passed + ?> - // Check if mailpoet_export URL param is present, and start auto-export. - let searchParams = new URLSearchParams(window.location.search); - if ( searchParams.has('mailpoet_export') ) { - jQuery( '.zbs-segment-export-mailpoet' ).click(); - } + // Export segment as MailPoet list. + jQuery( '.zbs-segment-export-mailpoet' ).off( 'click' ).on( 'click', function ( e ) { + let exportButton = jQuery( e.target ); + jpcrm_segment_export_to_mailpoet( exportButton ); + }); - DAL->segments->getSegmentAudience( $segment_id, 0, 100000, 'ID', 'DESC', false, false, $retrieve_fields ); + try { - $segment = $zbs->DAL->segments->getSegment( $segment_id ); + $retrieve_fields = array( 'email' ); + $segment_contacts = $zbs->DAL->segments->getSegmentAudience( $segment_id, 0, 100000, 'ID', 'DESC', false, false, $retrieve_fields ); - if ( ! empty( $segment ) && is_array( $segment_contacts ) ) { + $segment = $zbs->DAL->segments->getSegment( $segment_id ); - $valid_emails = array_filter( $segment_contacts, function( $sc ) { - return zeroBSCRM_validateEmail( $sc['email'] ); - } ); + if ( ! empty( $segment ) && is_array( $segment_contacts ) ) { - $count_valid_emails = count( $valid_emails ); - $extra_message = ''; - if ( $count_valid_emails > 500 ) { - $extra_message = __('This might take a while.','zero-bs-crm'); - } + $valid_emails = array_filter( + $segment_contacts, + function ( $sc ) { + return zeroBSCRM_validateEmail( $sc['email'] ); + } + ); - $list_name = $this->get_export_list_name( $segment['name'] ); - $list_id = $zbs->modules->mailpoet->reset_mailpoet_list_by_segment_name( $list_name ); - - if ( ! empty( $list_id ) ) { - wp_send_json( - array( - 'jpcrm_segment_ID' => $segment_id, - 'mailpoet_list_ID' => $list_id, - 'success' => true, - 'total_contacts' => $count_valid_emails, - 'lang' => array( - 'export_in_progress' => __('Export in progress','zero-bs-crm'), - 'export_finished' => __('Export finished','zero-bs-crm'), - 'export_in_progress_long' => __('This Segment is being exported to a MailPoet List.','zero-bs-crm') . ' ' . $extra_message, - 'export_finished_long' => __('The export process is now complete. Click the button below to view the list of subscribers.','zero-bs-crm'), - 'go_to_mailpoet_list' => __('Go to MailPoet','zero-bs-crm'), + $count_valid_emails = count( $valid_emails ); + $extra_message = ''; + if ( $count_valid_emails > 500 ) { + $extra_message = __( 'This might take a while.', 'zero-bs-crm' ); + } + + $list_name = $this->get_export_list_name( $segment['name'] ); + $list_id = $zbs->modules->mailpoet->reset_mailpoet_list_by_segment_name( $list_name ); + + if ( ! empty( $list_id ) ) { + wp_send_json( + array( + 'jpcrm_segment_ID' => $segment_id, + 'mailpoet_list_ID' => $list_id, + 'success' => true, + 'total_contacts' => $count_valid_emails, + 'lang' => array( + 'export_in_progress' => __( 'Export in progress', 'zero-bs-crm' ), + 'export_finished' => __( 'Export finished', 'zero-bs-crm' ), + 'export_in_progress_long' => __( 'This Segment is being exported to a MailPoet List.', 'zero-bs-crm' ) . ' ' . $extra_message, + 'export_finished_long' => __( 'The export process is now complete. Click the button below to view the list of subscribers.', 'zero-bs-crm' ), + 'go_to_mailpoet_list' => __( 'Go to MailPoet', 'zero-bs-crm' ), + ), ) - ) - ); + ); + } } - } - } catch ( \Throwable $th ) { - wp_send_json( - array( - 'success' => false, - 'lang' => array( - 'error_title' => __('Something went wrong','zero-bs-crm'), - 'error_message' => $th->getMessage(), + } catch ( \Throwable $th ) { + wp_send_json( + array( + 'success' => false, + 'lang' => array( + 'error_title' => __( 'Something went wrong', 'zero-bs-crm' ), + 'error_message' => $th->getMessage(), + ), ) - ) - ); + ); + } } - } - // empty handed - wp_send_json( - array( - 'segmentID' => $segment_id, - 'success' => false, - 'lang' => array( - 'error_title' => __('Something went wrong','zero-bs-crm'), - 'error_message' => __('The segment could not be exported to MailPoet','zero-bs-crm'), + // empty handed + wp_send_json( + array( + 'segmentID' => $segment_id, + 'success' => false, + 'lang' => array( + 'error_title' => __( 'Something went wrong', 'zero-bs-crm' ), + 'error_message' => __( 'The segment could not be exported to MailPoet', 'zero-bs-crm' ), + ), ) - ) - ); - - } ); + ); + } + ); /** * AJAX endpoint to export to MailPoet Segment, by batch */ - add_action( 'wp_ajax_jpcrm_mailpoet_export_segment', function () { + add_action( + 'wp_ajax_jpcrm_mailpoet_export_segment', + function () { - header( 'Content-Type: application/json' ); + header( 'Content-Type: application/json' ); - global $zbs; - - try { - - if ( ! current_user_can( 'admin_zerobs_customers' ) ) { - echo esc_html__( 'Not enough permissions.', 'zero-bs-crm' ); - exit( 0 ); - } + global $zbs; - if ( ! isset( $_POST['segment_id'] ) || ! isset( $_POST['mailpoet_id'] ) ) { - echo esc_html__( 'Not enough data provided to perform export.', 'zero-bs-crm' ); - exit( 0 ); - } + try { - $segment_id = (int) sanitize_text_field( $_POST['segment_id'] ); - $mailpoet_id = (int) sanitize_text_field( $_POST['mailpoet_id'] ); - $page = (int) sanitize_text_field( $_POST['page'] ); - $per_page = (int) sanitize_text_field( $_POST['per_page'] ); + if ( ! current_user_can( 'admin_zerobs_customers' ) ) { + echo esc_html__( 'Not enough permissions.', 'zero-bs-crm' ); + exit( 0 ); + } - $retrieve_fields = $retrieve_fields = array( 'email', 'fname', 'lname' ); - $contacts_batch = $zbs->DAL->segments->getSegmentAudience( $segment_id, $page, $per_page, 'ID', 'DESC', false, false, $retrieve_fields ); + if ( ! isset( $_POST['segment_id'] ) || ! isset( $_POST['mailpoet_id'] ) ) { + echo esc_html__( 'Not enough data provided to perform export.', 'zero-bs-crm' ); + exit( 0 ); + } - // Create MailPoet Mailing List - $response = $zbs->modules->mailpoet->contacts_to_subscribers( $mailpoet_id, $contacts_batch ); + $segment_id = (int) sanitize_text_field( $_POST['segment_id'] ); + $mailpoet_id = (int) sanitize_text_field( $_POST['mailpoet_id'] ); + $page = (int) sanitize_text_field( $_POST['page'] ); + $per_page = (int) sanitize_text_field( $_POST['per_page'] ); - if ( ! empty( $response['success'] ) ) { + $retrieve_fields = $retrieve_fields = array( 'email', 'fname', 'lname' ); + $contacts_batch = $zbs->DAL->segments->getSegmentAudience( $segment_id, $page, $per_page, 'ID', 'DESC', false, false, $retrieve_fields ); - $is_last_batch = ( count($contacts_batch) < $per_page ); + // Create MailPoet Mailing List + $response = $zbs->modules->mailpoet->contacts_to_subscribers( $mailpoet_id, $contacts_batch ); - wp_send_json( - array( - 'success' => true, - 'segmentID' => $segment_id, - 'current_page' => $page, - 'is_last_batch' => $is_last_batch - ) - ); + if ( ! empty( $response['success'] ) ) { - } else { + $is_last_batch = ( count( $contacts_batch ) < $per_page ); - wp_send_json( - array( - 'segmentID' => $segment_id, - 'success' => false, - 'error' => $response['error'], - 'lang' => array( - 'error_title' => __('Something went wrong','zero-bs-crm'), - 'error_message' => __('The segment could not be exported to MailPoet','zero-bs-crm'), + wp_send_json( + array( + 'success' => true, + 'segmentID' => $segment_id, + 'current_page' => $page, + 'is_last_batch' => $is_last_batch, ) - ) - ); - - } + ); + + } else { + + wp_send_json( + array( + 'segmentID' => $segment_id, + 'success' => false, + 'error' => $response['error'], + 'lang' => array( + 'error_title' => __( 'Something went wrong', 'zero-bs-crm' ), + 'error_message' => __( 'The segment could not be exported to MailPoet', 'zero-bs-crm' ), + ), + ) + ); - } catch ( \Throwable $th ) { + } + } catch ( \Throwable $th ) { - wp_send_json( - array( - 'segmentID' => $segment_id, - 'success' => false, - 'error' => $th->getMessage(), - 'lang' => array( - 'error_title' => __('Something went wrong','zero-bs-crm'), - 'error_message' => __('The segment could not be exported to MailPoet','zero-bs-crm'), - ) - ) - ); + wp_send_json( + array( + 'segmentID' => $segment_id, + 'success' => false, + 'error' => $th->getMessage(), + 'lang' => array( + 'error_title' => __( 'Something went wrong', 'zero-bs-crm' ), + 'error_message' => __( 'The segment could not be exported to MailPoet', 'zero-bs-crm' ), + ), + ) + ); + } } - - } ); - + ); /** * AJAX endpoint to retrieve summary data about a mailpoet list */ - add_action( 'wp_ajax_jpcrm_mailpoet_retrieve_list_summary', function () { - - header( 'Content-Type: application/json' ); + add_action( + 'wp_ajax_jpcrm_mailpoet_retrieve_list_summary', + function () { - global $zbs; + header( 'Content-Type: application/json' ); - try { + global $zbs; - if ( ! current_user_can( 'admin_zerobs_customers' ) ) { - echo esc_html__( 'Not enough permissions.', 'zero-bs-crm' ); - exit( 0 ); - } + try { - if ( ! isset( $_POST['list_name'] ) ) { - echo esc_html__( 'Not enough data provided to perform export.', 'zero-bs-crm' ); - exit( 0 ); - } + if ( ! current_user_can( 'admin_zerobs_customers' ) ) { + echo esc_html__( 'Not enough permissions.', 'zero-bs-crm' ); + exit( 0 ); + } - $list_name = sanitize_text_field( $_POST['list_name'] ); - $list_suffix = (int)sanitize_text_field( $_POST['add_suffix'] ); + if ( ! isset( $_POST['list_name'] ) ) { + echo esc_html__( 'Not enough data provided to perform export.', 'zero-bs-crm' ); + exit( 0 ); + } - // add ` | CRM`? - if ( $list_suffix ){ - $list_name = $this->get_export_list_name( $list_name ); - } + $list_name = sanitize_text_field( $_POST['list_name'] ); + $list_suffix = (int) sanitize_text_field( $_POST['add_suffix'] ); - $list_details = $zbs->modules->mailpoet->get_mailpoet_list_summary_by_name( $list_name ); + // add ` | CRM`? + if ( $list_suffix ) { + $list_name = $this->get_export_list_name( $list_name ); + } + $list_details = $zbs->modules->mailpoet->get_mailpoet_list_summary_by_name( $list_name ); - if ( ! is_array( $list_details ) ) { - // nope - wp_send_json( false ); - } else { - // success - wp_send_json( $list_details ); + if ( ! is_array( $list_details ) ) { + // nope + wp_send_json( false ); + } else { + // success + wp_send_json( $list_details ); + } + } catch ( \Throwable $th ) { + wp_send_json_error( array( 'fail' => 1 ), 500 ); } - } catch ( \Throwable $th ) { - wp_send_json_error( array( 'fail' => 1 ), 500 ); } - - } ); - + ); } - - /** * Returns the name that a segment would be exported to */ @@ -336,6 +350,5 @@ public function get_export_list_name( $list_name = '' ) { ##/WLREMOVE return $name; - } } diff --git a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-segment-conditions.php b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-segment-conditions.php index d8c60d644246..9634742a633e 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-segment-conditions.php +++ b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet-segment-conditions.php @@ -1,5 +1,5 @@ -conditions['is_mailpoet_customer'] = new \Segment_Condition_Mailpoet_Subscriber(); - } } diff --git a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet.php b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet.php index dd460dbf1f42..cfad4e1e3739 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet.php +++ b/projects/plugins/crm/modules/mailpoet/includes/class-mailpoet.php @@ -1,5 +1,5 @@ - 'crm-mail-poet-hub', // note needs to match `$zbs->slugs['mailpoet'] and can't use `*mailpoet*` as the plugin inteferes with styles - 'settings' => 'mailpoet', - 'add-edit' => 'zbs-add-edit', + 'hub' => 'crm-mail-poet-hub', // note needs to match `$zbs->slugs['mailpoet'] and can't use `*mailpoet*` as the plugin inteferes with styles + 'settings' => 'mailpoet', + 'add-edit' => 'zbs-add-edit', ); /** @@ -104,7 +104,7 @@ class Mailpoet { */ public $urls = array( - 'install_mailpoet' => '/wp-admin/plugin-install.php?tab=plugin-information&plugin=mailpoet' + 'install_mailpoet' => '/wp-admin/plugin-install.php?tab=plugin-information&plugin=mailpoet', ); @@ -121,7 +121,7 @@ public function __construct() { // Initialise Settings $this->init_settings(); - + // Initialise Features $this->init_features(); @@ -138,10 +138,8 @@ public function __construct() { $this->register_styles_scripts(); } - } - /** * Main Class Instance. * @@ -149,45 +147,41 @@ public function __construct() { * * @since 2.0 * @static - * @see + * @see * @return Mailpoet_Sync main instance */ public static function instance() { - if ( is_null( self::$_instance ) ) { + if ( self::$_instance === null ) { self::$_instance = new self(); } return self::$_instance; } - /** * Define any key vars. */ - private function definitions(){ + private function definitions() { // for now there is ONLY local, but precursors.. define( 'JPCRM_MAILPOET_MODE_LOCAL', 0 ); - define( 'JPCRM_MAILPOET_MODE_API', 1 ); - + define( 'JPCRM_MAILPOET_MODE_API', 1 ); } - /** * * Checks dependencies * * @return bool - * */ public function check_dependencies() { global $zbs; - $core_reqs = array( + $core_reqs = array( 'req_core_ver' => $zbs::VERSION, // will match current core version 'req_DAL_ver' => '3.0', ); - $plugin_reqs = array( + $plugin_reqs = array( 'name' => 'MailPoet', 'slug' => 'mailpoet/mailpoet.php', 'link' => 'https://wordpress.org/plugins/mailpoet/', @@ -206,23 +200,20 @@ public function check_dependencies() { return false; } - /** * Initialise Settings */ private function init_settings() { - - $this->settings = new \WHWPConfigExtensionsLib( $this->config_key, $this->default_settings() ); + $this->settings = new \WHWPConfigExtensionsLib( $this->config_key, $this->default_settings() ); } /** * Retrieve Settings */ public function get_settings() { - - return $this->settings->getAll(); + return $this->settings->getAll(); } /** @@ -238,11 +229,10 @@ private function init_hooks() { // Adds Tools menu subitem add_filter( 'zbs-tools-menu', array( $this, 'add_tools_menu_sub_item_link' ) ); // Learn menu - add_action( 'wp_after_admin_bar_render', array( $this, 'render_learn_menu'), 12 ); + add_action( 'wp_after_admin_bar_render', array( $this, 'render_learn_menu' ), 12 ); // Admin menu add_filter( 'zbs_menu_wpmenu', array( $this, 'add_wp_pages' ), 10, 1 ); - // JPCRM effecting: // Add MailPoet related info to CRM external source infobox @@ -259,7 +249,6 @@ private function init_hooks() { // add a position to the MailPoet segment condition category positions array add_filter( 'jpcrm_segment_condition_category_positions', array( $this, 'add_segments_condition_category_positions' ) ); - } /** @@ -313,12 +302,10 @@ private function init_features() { $this->mailpoet_export_segment = Mailpoet_Export_Segment_To_MailPoet::instance(); // Segment conditions - require_once( JPCRM_MAILPOET_ROOT_PATH . 'includes/class-mailpoet-segment-conditions.php' ); + require_once JPCRM_MAILPOET_ROOT_PATH . 'includes/class-mailpoet-segment-conditions.php'; $this->segment_conditions = MailPoet_Segment_Conditions::instance(); - } - /** * Autoload page AJAX */ @@ -326,33 +313,27 @@ private function load_ajax() { $admin_page_directories = jpcrm_get_directories( JPCRM_MAILPOET_ROOT_PATH . 'admin' ); - if ( is_array( $admin_page_directories ) ){ + if ( is_array( $admin_page_directories ) ) { - foreach ( $admin_page_directories as $directory ){ + foreach ( $admin_page_directories as $directory ) { $files = scandir( JPCRM_MAILPOET_ROOT_PATH . 'admin/' . $directory ); - - if ( is_array( $files ) ){ - foreach ( $files as $file ){ + if ( is_array( $files ) ) { + + foreach ( $files as $file ) { // find files `*.ajax.*` - if ( strrpos( $file, '.ajax.' ) > 0 ){ + if ( strrpos( $file, '.ajax.' ) > 0 ) { // load it - require_once( JPCRM_MAILPOET_ROOT_PATH . 'admin/' . $directory . '/' . $file ); + require_once JPCRM_MAILPOET_ROOT_PATH . 'admin/' . $directory . '/' . $file; } - } - } - - } - } - } /** @@ -374,17 +355,17 @@ public function contact_query_quickfilter_addition( $wheres, $quick_filter_key ) global $ZBSCRM_t; // is a MailPoet subscriber? (Could be copied/generalised for other ext sources) - if ( $quick_filter_key == 'mailpoet_subscriber' ){ - $wheres['is_mailpoet_customer'] = array( - 'ID','IN', - '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . " WHERE zbss_objtype = " . ZBS_TYPE_CONTACT . " AND zbss_source = %s)", - array( 'mailpoet' ) - ); - } - - return $wheres; - } + if ( $quick_filter_key == 'mailpoet_subscriber' ) { + $wheres['is_mailpoet_customer'] = array( + 'ID', + 'IN', + '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_CONTACT . ' AND zbss_source = %s)', + array( 'mailpoet' ), + ); + } + return $wheres; + } /** * Hook in to new contact log creation and add string manipulation @@ -392,13 +373,13 @@ public function contact_query_quickfilter_addition( $wheres, $quick_filter_key ) */ public function new_contact_log_override( $note_long_description, $source_key, $uid ) { - if ( $source_key == 'mailpoet' ){ + if ( $source_key == 'mailpoet' ) { - $note_long_description = __( 'Synchronised from MailPoet', 'zero-bs-crm' ) . '  '; + $note_long_description = __( 'Synchronised from MailPoet', 'zero-bs-crm' ) . '  '; - } + } - return $note_long_description; + return $note_long_description; } /** @@ -406,49 +387,43 @@ public function new_contact_log_override( $note_long_description, $source_key, $ * (previously on `init`) */ public function register_styles_scripts() { - } - /** * Filter settings tabs, adding this extension * (previously `load_settings_tab`) * * @param array $tabs */ - public function add_settings_tab( $tabs ){ - + public function add_settings_tab( $tabs ) { + // Append our tab if enabled if ( $this->settings_tab ) { - $main_tab = $this->slugs['settings']; - $tabs[ $main_tab ] = array( - 'name' => $this->ext_name, - 'ico' => '', + $main_tab = $this->slugs['settings']; + $tabs[ $main_tab ] = array( + 'name' => $this->ext_name, + 'ico' => '', 'submenu' => array(), ); - + } return $tabs; - } - /** * Return default settings */ public function default_settings() { - return require( JPCRM_MAILPOET_ROOT_PATH . 'includes/jpcrm-mailpoet-default-settings.php' ); - + return require JPCRM_MAILPOET_ROOT_PATH . 'includes/jpcrm-mailpoet-default-settings.php'; } - /** * Main page addition */ - function add_wp_pages( $menu_array=array() ) { + function add_wp_pages( $menu_array = array() ) { // add a submenu item to main CRM menu $menu_array['jpcrm']['subitems']['mailpoet'] = array( @@ -462,9 +437,7 @@ function add_wp_pages( $menu_array=array() ) { ); return $menu_array; - - } - + } /** * Adds Tools menu sub item @@ -472,32 +445,30 @@ function add_wp_pages( $menu_array=array() ) { public function add_tools_menu_sub_item_link( $menu_items ) { global $zbs; - + $menu_items[] = ' MailPoet Sync'; - - return $menu_items; + return $menu_items; } - /** * Output learn menu */ - public function render_learn_menu(){ + public function render_learn_menu() { - if ( $this->is_hub_page() ){ + if ( $this->is_hub_page() ) { global $zbs; - $learn_content = '

' . __( "Here you can import your MailPoet data.", 'zerobscrm' ) . '

'; - + $learn_content = '

' . __( 'Here you can import your MailPoet data.', 'zerobscrm' ) . '

'; + // output $zbs->learn_menu->render_generic_learn_menu( 'MailPoet Sync', '', '', true, - __( "Import MailPoet Subscribers", "zerobscrm" ), + __( 'Import MailPoet Subscribers', 'zerobscrm' ), $learn_content, $zbs->urls['kb-mailpoet'], false, @@ -505,42 +476,39 @@ public function render_learn_menu(){ '' ); - } } - /** * Load the file for a given page * * @param string $page_name (e.g. `settings/main`) */ - public function load_admin_page( $page_name ){ - - jpcrm_load_admin_page( $page_name, JPCRM_MAILPOET_ROOT_PATH ); + public function load_admin_page( $page_name ) { + jpcrm_load_admin_page( $page_name, JPCRM_MAILPOET_ROOT_PATH ); } - /** * Append/override MailPoet related info to CRM external source infobox * * @param string $html - * @param array $external_source + * @param array $external_source */ public function override_crm_external_source_infobox( $html, $external_source ) { global $zbs; - - if ( $external_source['source'] == 'mailpoet' ){ + + if ( $external_source['source'] == 'mailpoet' ) { // verify subscriber is still in MailPoet before showing a link: $potential_subscriber = $this->get_mailpoet_subscriber_by_subscriber_id( $external_source['unique_id'] ); - if ( $potential_subscriber ){ + if ( $potential_subscriber ) { // retrieve origin info (where available) - /* Not in v1.0 of this module + /* + Not in v1.0 of this module $origin_str = ''; $origin_detail = $zbs->DAL->hydrate_origin( $external_source['origin'] ); if ( is_array( $origin_detail ) && isset( $origin_detail['origin_type'] ) && $origin_detail['origin_type'] == 'domain' ){ @@ -553,41 +521,34 @@ public function override_crm_external_source_infobox( $html, $external_source ) // adds button to subscriber page // e.g. http://july.local/wp-admin/admin.php?page=mailpoet-subscribers#/stats/1 - $mailpoet_stats_link = $this->get_mailpoet_sub_stats_link( $external_source['unique_id'] ); //admin_url( 'post.php?post=' . $external_source['unique_id'] . '&action=edit' ); + $mailpoet_stats_link = $this->get_mailpoet_sub_stats_link( $external_source['unique_id'] ); // admin_url( 'post.php?post=' . $external_source['unique_id'] . '&action=edit' ); - switch ( $external_source['objtype'] ){ + switch ( $external_source['objtype'] ) { case ZBS_TYPE_CONTACT: - $html = '
' . sprintf( __( 'Subscriber ID #%s', 'zero-bs-crm' ), $external_source['unique_id'] ) . ' ' . __( 'View Subscriber', 'zero-bs-crm' ) . '
'; break; } - } else { // probably has been deleted in MailPoet // (where user had a delete_action option of `none|add_note`) - switch ( $external_source['objtype'] ){ + switch ( $external_source['objtype'] ) { case ZBS_TYPE_CONTACT: - $html = '
' . sprintf( __( 'Subscriber ID #%s', 'zero-bs-crm' ), $external_source['unique_id'] ) . ' ' . __( 'Subscriber not found', 'zero-bs-crm' ) . '
'; break; } - } - } return $html; - } - /** * Returns the total number of mailpoet imported contacts present in CRM */ @@ -595,72 +556,67 @@ public function get_crm_mailpoet_contact_count() { global $zbs; - return (int)$zbs->DAL->contacts->getContacts( + return (int) $zbs->DAL->contacts->getContacts( array( 'externalSource' => 'mailpoet', 'count' => true, 'ignoreowner' => true, - ) - ); - + ) + ); } - /** * Returns bool: is the loading page, our hub page * * @return bool hub page */ - public function is_hub_page(){ + public function is_hub_page() { $page = ''; - if ( isset( $_GET['page'] ) ){ + if ( isset( $_GET['page'] ) ) { $page = sanitize_text_field( $_GET['page'] ); } - if ( $page == $this->slugs['hub'] ){ + if ( $page == $this->slugs['hub'] ) { return true; } return false; - } /** * Returns bool: true if the page is zbs-add-edit * - * @return bool + * @return bool */ - public function is_add_edit_page(){ + public function is_add_edit_page() { $page = ''; - if ( isset( $_GET['page'] ) ){ + if ( isset( $_GET['page'] ) ) { $page = sanitize_text_field( $_GET['page'] ); } // specifically segment add-edit $type = ''; - if ( isset( $_GET['zbstype'] ) ){ + if ( isset( $_GET['zbstype'] ) ) { $type = sanitize_text_field( $_GET['zbstype'] ); } - if ( $type !== 'segment' ){ + if ( $type !== 'segment' ) { return false; } return $page == $this->slugs['add-edit']; } - - /** * Returns Summarised JPCRM MailPoet stats * Ripe for expansion * - * @return + * @return */ public function get_jpcrm_mailpoet_latest_stats() { @@ -669,44 +625,46 @@ public function get_jpcrm_mailpoet_latest_stats() { 'subscribers_synced' => $this->get_crm_mailpoet_contact_count(), ); - } /** * Returns link to MailPoet subscriber * - * @param int $subscriber_id + * @param int $subscriber_id * or * @param string $email * * @return string URL */ - public function get_mailpoet_sub_stats_link( $subscriber_id = false, $email = false ){ + public function get_mailpoet_sub_stats_link( $subscriber_id = false, $email = false ) { global $zbs; // sits at /wp-admin/admin.php?page=mailpoet-subscribers#/stats/4 $id = false; - if ( $subscriber_id > 0 ){ + if ( $subscriber_id > 0 ) { $id = $subscriber_id; - } elseif ( !empty( $email ) ) { - - $id = $zbs->DAL->contacts->getContact( -1, array( - 'email' => $email, - 'onlyID' => true, - 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ) - )); + } elseif ( ! empty( $email ) ) { + + $id = $zbs->DAL->contacts->getContact( + -1, + array( + 'email' => $email, + 'onlyID' => true, + 'ignoreowner' => zeroBSCRM_DAL2_ignoreOwnership( ZBS_TYPE_CONTACT ), + ) + ); } - if ( $id ){ + if ( $id ) { return '/wp-admin/admin.php?page=mailpoet-subscribers#/stats/' . $id; } - return '#'; + return '#'; } /** @@ -716,23 +674,21 @@ public function get_mailpoet_sub_stats_link( $subscriber_id = false, $email = fa * * @return string URL */ - public function get_mailpoet_list_subs_link( $segment_id ){ + public function get_mailpoet_list_subs_link( $segment_id ) { // sits at /wp-admin/admin.php?page=mailpoet-segments#/edit/3 return site_url( '/wp-admin/admin.php?page=mailpoet-segments#/edit/' . $segment_id ); - } /** * Returns URL to hop to local Mailpoet wp-admin - * + * * @return string URL */ public function get_local_mailpoet_admin_url() { return site_url( '/wp-admin/admin.php?page=mailpoet-newsletters' ); - } /** @@ -742,81 +698,78 @@ public function get_local_mailpoet_admin_url() { * * @return string URL */ - public function get_mailpoet_list_tagged_link( $tag_id ){ + public function get_mailpoet_list_tagged_link( $tag_id ) { - - return site_url( '/wp-admin/admin.php?page=mailpoet-subscribers#/filter[tag=' . $tag_id . ']'); + return site_url( '/wp-admin/admin.php?page=mailpoet-subscribers#/filter[tag=' . $tag_id . ']' ); } - // =============================================================================== // =========== MailPoet DAL ====================================================== - /* * Retrieve MailPoet data on a subscriber (from their MAILPOET subscriber ID) */ - public function get_mailpoet_subscriber_by_subscriber_id( $subscriber_id, $with_meta = false, $with_tags = false ){ + public function get_mailpoet_subscriber_by_subscriber_id( $subscriber_id, $with_meta = false, $with_tags = false ) { // currently there's no direct MailPoet API way of doing this // so here we use the subscriber ID (MP Unique ID) to find the contact via external source search // ... then use their main email. - // ... this is flawed, because users can change emails, or use alias emails, + // ... this is flawed, because users can change emails, or use alias emails, // ... but until MailPoet has a `getSubscriberByID()` endpoint... // gh-2565 global $zbs; - $potential_contact = $zbs->DAL->contacts->getContact( -1, array( - - 'externalSource' => 'mailpoet', - 'externalSourceUID' => $subscriber_id, - - )); + $potential_contact = $zbs->DAL->contacts->getContact( + -1, + array( - if ( is_array( $potential_contact ) && isset( $potential_contact['email'] ) ){ + 'externalSource' => 'mailpoet', + 'externalSourceUID' => $subscriber_id, - return $this->get_mailpoet_subscriber_by_email( $potential_contact['email'], $with_meta, $with_tags ); + ) + ); + if ( is_array( $potential_contact ) && isset( $potential_contact['email'] ) ) { - } + return $this->get_mailpoet_subscriber_by_email( $potential_contact['email'], $with_meta, $with_tags ); - return false; + } + return false; } /* * Retrieve MailPoet data on a subscriber */ - public function get_mailpoet_subscriber_by_email( $email, $with_meta = false, $with_tags = false ){ - + public function get_mailpoet_subscriber_by_email( $email, $with_meta = false, $with_tags = false ) { // API+API Method // https://github.com/mailpoet/mailpoet/blob/trunk/doc/api_methods/GetSubscriber.md if ( class_exists( \MailPoet\API\API::class ) ) { - + // load api - $mailpoet_api = \MailPoet\API\API::MP('v1'); + $mailpoet_api = \MailPoet\API\API::MP( 'v1' ); - // attempt retrieval + // attempt retrieval try { - // basic retrieval + // basic retrieval $subscriber = $mailpoet_api->getSubscriber( $email ); - $lists = $this->get_mailpoet_lists_summary(); + $lists = $this->get_mailpoet_lists_summary(); // hydrate subscriptions - if ( is_array( $subscriber['subscriptions'] ) ){ + if ( is_array( $subscriber['subscriptions'] ) ) { $full_subscriptions_array = array(); - foreach ( $subscriber['subscriptions'] as $sub ){ + foreach ( $subscriber['subscriptions'] as $sub ) { $new_sub = $sub; // find sub list - foreach ( $lists as $list ){ + foreach ( $lists as $list ) { - if ( $new_sub['segment_id'] == $list['id'] ){ + if ( $new_sub['segment_id'] == $list['id'] ) { // add some useful attributes not present in raw subscriptions obj $new_sub['segment_name'] = $list['name']; @@ -824,7 +777,6 @@ public function get_mailpoet_subscriber_by_email( $email, $with_meta = false, $w $new_sub['segment_description'] = $list['description']; } - } $full_subscriptions_array[] = $new_sub; @@ -836,20 +788,18 @@ public function get_mailpoet_subscriber_by_email( $email, $with_meta = false, $w return $subscriber; - } catch (\Exception $e) { - + } catch ( \Exception $e ) { } - } - - /* Bunch of ways could seemingly do this without API, tried the following with some luck, - but API method above more reliable in this instance. Would need to further check with + /* + Bunch of ways could seemingly do this without API, tried the following with some luck, + but API method above more reliable in this instance. Would need to further check with MailPoet team if wanted to switch from API for one of these methods... // here's adirect call method - $subscriber = Subscriber::findOne( $email )->asArray(); + $subscriber = Subscriber::findOne( $email )->asArray(); // or by MP id... $SubscribersRepository = ContainerWrapper::getInstance()->get(SubscribersRepository::class); @@ -861,19 +811,15 @@ public function get_mailpoet_subscriber_by_email( $email, $with_meta = false, $w // ... adding tags $subscriber_array['tags'] = array(); if ( method_exists( $subscriber, 'getSubscriberTags' ) ){ - + $subscriber_array['tags'] = $subscriber->getSubscriberTags(); } return $subscriber_array; */ - } - - - /** * Return an array of mailpoet lists which a contact is in * @@ -884,69 +830,64 @@ public function get_mailpoet_lists_for_contact_from_email( $email ) { $subscriber = $this->get_mailpoet_subscriber_by_email( $email ); // return just the lists (Segments in MP nomenclature) - if ( is_array( $subscriber ) && isset( $subscriber['segments'] ) ){ + if ( is_array( $subscriber ) && isset( $subscriber['segments'] ) ) { return $subscriber['segments']; } // ... actually we use `subscriptions` which amounts to the same thing - if ( is_array( $subscriber ) && isset( $subscriber['subscriptions'] ) ){ + if ( is_array( $subscriber ) && isset( $subscriber['subscriptions'] ) ) { return $subscriber['subscriptions']; } return array(); - } - /** - * Retrieve MailPoet list summary data by name - * (currently needs to retrieve all lists and enumerate) - */ - public function get_mailpoet_list_summary_by_name( $mailpoet_list_name = '' ){ + * Retrieve MailPoet list summary data by name + * (currently needs to retrieve all lists and enumerate) + */ + public function get_mailpoet_list_summary_by_name( $mailpoet_list_name = '' ) { $lists = $this->get_mailpoet_lists_summary(); - if ( is_array( $lists ) ){ + if ( is_array( $lists ) ) { - foreach( $lists as $list ){ + foreach ( $lists as $list ) { - if ( $list['name'] == $mailpoet_list_name ){ + if ( $list['name'] == $mailpoet_list_name ) { return $list; - - } + } } - } return false; - } /** - * Retrieve MailPoet lists summary data - */ - public function get_mailpoet_lists_summary( $keyed_by_mailpoet_segment_id = false ){ + * Retrieve MailPoet lists summary data + */ + public function get_mailpoet_lists_summary( $keyed_by_mailpoet_segment_id = false ) { // https://github.com/mailpoet/mailpoet/blob/trunk/doc/api_methods/GetLists.md if ( class_exists( \MailPoet\API\API::class ) ) { - + // load api - $mailpoet_api = \MailPoet\API\API::MP('v1'); + $mailpoet_api = \MailPoet\API\API::MP( 'v1' ); - // attempt retrieval + // attempt retrieval try { - + $list_of_lists = $mailpoet_api->getLists(); - if ( $keyed_by_mailpoet_segment_id ){ + if ( $keyed_by_mailpoet_segment_id ) { $keyed_array_of_lists = array(); - foreach ( $list_of_lists as $list ){ + foreach ( $list_of_lists as $list ) { $keyed_array_of_lists[ $list['id'] ] = $list; } @@ -956,39 +897,33 @@ public function get_mailpoet_lists_summary( $keyed_by_mailpoet_segment_id = fals return $list_of_lists; - } catch (\Exception $e) { - + } catch ( \Exception $e ) { } - } return false; - } - /* * Retrieve an int count of all MailPoet subscribers */ - public function get_all_mailpoet_subscribers_count(){ + public function get_all_mailpoet_subscribers_count() { return $this->get_all_mailpoet_subscribers( false, false, true ); - } - /* * Retrieve MailPoet subscribers (all of them) * Wrapper for `get_mailpoet_subscribers()` */ - public function get_all_mailpoet_subscribers( - $limit = 50, - $offset = 0, - $count = false, - $with_meta = false, - $with_tags = false - ){ + public function get_all_mailpoet_subscribers( + $limit = 50, + $offset = 0, + $count = false, + $with_meta = false, + $with_tags = false + ) { return $this->get_mailpoet_subscribers( false, @@ -998,13 +933,11 @@ public function get_all_mailpoet_subscribers( $offset, $count ); - } - /* * Retrieve MailPoet subscribers - * + * * @param int $limit * @param int $offset * @param int $count @@ -1020,32 +953,32 @@ public function get_mailpoet_subscribers( $count = false, $with_meta = false, $with_tags = false - ){ + ) { // https://github.com/mailpoet/mailpoet/blob/trunk/doc/api_methods/GetSubscribers.md // https://github.com/mailpoet/mailpoet/blob/trunk/doc/api_methods/GetSubscribersCount.md if ( class_exists( \MailPoet\API\API::class ) ) { - + // load api - $mailpoet_api = \MailPoet\API\API::MP('v1'); + $mailpoet_api = \MailPoet\API\API::MP( 'v1' ); - // attempt retrieval + // attempt retrieval try { // build params $filters = array(); - if ( !empty( $status ) ){ + if ( ! empty( $status ) ) { $filters['status'] = $status; } - if ( $list_id > 0 ){ + if ( $list_id > 0 ) { $filters['listId'] = $list_id; } - if ( $min_updated_at > 0 ){ + if ( $min_updated_at > 0 ) { $filters['minUpdatedAt'] = $min_updated_at; } - + // if count, return that - if ( $count ){ + if ( $count ) { return $mailpoet_api->getSubscribersCount( $filters @@ -1056,40 +989,38 @@ public function get_mailpoet_subscribers( // as at 19/10/22 the MailPoet API endpoint does not yet support returning segments/tags // $with_meta, $with_tags - // return + // return return $mailpoet_api->getSubscribers( $filters, $limit, $offset ); - } catch (\Exception $e) { + } catch ( \Exception $e ) { // debug: echo 'MailPoet API Error: ' . $e->getMessage(); } - } return false; - } - - /* * Helper function to filter MailPoet lists by name. */ public function get_mailpoet_list_by_name( $name ) { - $mailpoet_api = \MailPoet\API\API::MP('v1'); - $lists = $mailpoet_api->getLists(); - $found = array_filter($lists, function ($i) use($name) { - return ($i['name'] == $name); - }); - - return array_pop($found); - } + $mailpoet_api = \MailPoet\API\API::MP( 'v1' ); + $lists = $mailpoet_api->getLists(); + $found = array_filter( + $lists, + function ( $i ) use ( $name ) { + return ( $i['name'] == $name ); + } + ); + return array_pop( $found ); + } /* * Creates a mew MailPoet mailing List. @@ -1097,10 +1028,10 @@ public function get_mailpoet_list_by_name( $name ) { */ public function reset_mailpoet_list_by_segment_name( $name ) { - $mailpoet_api = \MailPoet\API\API::MP('v1'); + $mailpoet_api = \MailPoet\API\API::MP( 'v1' ); $list = $this->get_mailpoet_list_by_name( $name ); - + // Delete all subscribers from this list if ( ! empty( $list ) && ! empty( $list['id'] ) ) { $mailpoet_api->deleteList( $list['id'] ); @@ -1113,9 +1044,11 @@ public function reset_mailpoet_list_by_segment_name( $name ) { $description = __( 'Created by Jetpack CRM', 'zero-bs-crm' ); ##/WLREMOVE - $list = $mailpoet_api->addList( array( - 'name' => $name, - 'description' => $description ) + $list = $mailpoet_api->addList( + array( + 'name' => $name, + 'description' => $description, + ) ); return $list['id']; @@ -1124,33 +1057,29 @@ public function reset_mailpoet_list_by_segment_name( $name ) { /* * Retrieve MailPoet setup status */ - public function get_mailpoet_setup_status(){ + public function get_mailpoet_setup_status() { // https://github.com/mailpoet/mailpoet/blob/trunk/doc/api_methods/IsSetupComplete.md if ( class_exists( \MailPoet\API\API::class ) ) { - + // load api - $mailpoet_api = \MailPoet\API\API::MP('v1'); + $mailpoet_api = \MailPoet\API\API::MP( 'v1' ); - // attempt retrieval + // attempt retrieval try { - - return $mailpoet_api->isSetupComplete(); - } catch (\Exception $e) { + return $mailpoet_api->isSetupComplete(); + } catch ( \Exception $e ) { } - } return false; - } // =========== / MailPoet Specific Migrations =================================== // =============================================================================== - // =============================================================================== // =========== MailPoet Specific Migrations ===================================== @@ -1158,8 +1087,7 @@ public function get_mailpoet_setup_status(){ /* * Migrations */ - private function run_migrations(){ - + private function run_migrations() { } // =========== / MailPoet Specific Migrations =================================== @@ -1172,14 +1100,14 @@ public function contacts_to_subscribers( $list_id, $subscribers ) { try { - $mailpoet_api = \MailPoet\API\API::MP('v1'); + $mailpoet_api = \MailPoet\API\API::MP( 'v1' ); - foreach( $subscribers as $sc ) { + foreach ( $subscribers as $sc ) { if ( ! zeroBSCRM_validateEmail( $sc['email'] ) ) { continue; } - + try { $subscriber = $mailpoet_api->getSubscriber( $sc['email'] ); @@ -1191,22 +1119,21 @@ public function contacts_to_subscribers( $list_id, $subscribers ) { $list_id, array( 'send_confirmation_email' => false, - 'schedule_welcome_email' => false, + 'schedule_welcome_email' => false, 'skip_subscriber_notification' => true, ) ); } - - } catch (APIException $th) { + } catch ( APIException $th ) { // Subscriber not found. Create new Subscriber if ( $th->getCode() === APIException::SUBSCRIBER_NOT_EXISTS ) { try { $mailpoet_api->addSubscriber( array( - 'email' => $sc['email'], + 'email' => $sc['email'], 'first_name' => $sc['fname'], - 'last_name' => $sc['lname'], + 'last_name' => $sc['lname'], ), array( $list_id ), array( @@ -1215,39 +1142,36 @@ public function contacts_to_subscribers( $list_id, $subscribers ) { 'skip_subscriber_notification' => true, ) ); - } catch (APIException $th) { + } catch ( APIException $th ) { return null; } } - } } return array( - 'success' => true + 'success' => true, ); - } catch (\Throwable $th) { + } catch ( \Throwable $th ) { return array( 'success' => false, - 'error' => zeroBSCRM_locale_utsToDatetime( time() ) . '] ' . $th->getMessage() + 'error' => zeroBSCRM_locale_utsToDatetime( time() ) . '] ' . $th->getMessage(), ); } - } - + } /* * Adds segment condition category positions (to effect the display order) */ public function add_segments_condition_category_positions( $positions = array() ) { - global $zbs; - - $positions['mailpoet'] = 11; + global $zbs; - return $positions; + $positions['mailpoet'] = 11; + return $positions; } } diff --git a/projects/plugins/crm/modules/mailpoet/includes/jpcrm-mailpoet-contact-tabs.php b/projects/plugins/crm/modules/mailpoet/includes/jpcrm-mailpoet-contact-tabs.php index 60d0cd956040..277c2ab37f19 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/jpcrm-mailpoet-contact-tabs.php +++ b/projects/plugins/crm/modules/mailpoet/includes/jpcrm-mailpoet-contact-tabs.php @@ -1,5 +1,5 @@ mailpoet_is_active() ){ - - // Initialise Hooks - $this->init_hooks(); - - } - - } - - - /** - * Main Class Instance. - * - * Ensures only one instance of MailPoet_Contact_Tabs is loaded or can be loaded. - * - * @since 2.0 - * @static - * @see - * @return MailPoet_Contact_Tabs main instance - */ - public static function instance(){ - if ( is_null( self::$_instance ) ) { - self::$_instance = new self(); - } - return self::$_instance; - } - - - - /** - * Initialise Hooks - */ + global $zbs; + + if ( $zbs->mailpoet_is_active() ) { + + // Initialise Hooks + $this->init_hooks(); + + } + } + + /** + * Main Class Instance. + * + * Ensures only one instance of MailPoet_Contact_Tabs is loaded or can be loaded. + * + * @since 2.0 + * @static + * @see + * @return MailPoet_Contact_Tabs main instance + */ + public static function instance() { + if ( self::$_instance === null ) { + self::$_instance = new self(); + } + return self::$_instance; + } + + /** + * Initialise Hooks + */ private function init_hooks() { - // add in tabs - add_filter( 'jetpack-crm-contact-vital-tabs', array( $this, 'append_info_tabs' ) , 10, 3 ); - + // add in tabs + add_filter( 'jetpack-crm-contact-vital-tabs', array( $this, 'append_info_tabs' ), 10, 3 ); + } - } + /** + * Wire in ant applicable tabs + */ + public function append_info_tabs( $array, $id, $contact ) { + global $zbs; + if ( ! is_array( $array ) ) { + $array = array(); + } - /** - * Wire in ant applicable tabs - */ - public function append_info_tabs( $array, $id, $contact ) { + // MailPoet Info + if ( $zbs->mailpoet_is_active() ) { + $array[] = array( + 'id' => 'mailpoet-tab', + 'name' => __( 'MailPoet', 'zero-bs-crm' ), + 'content' => $this->generate_mailpoet_tab_html( $id, $contact ), + ); + } - global $zbs; + return $array; + } - if ( !is_array($array) ){ - $array = array(); - } + /** + * Draw the Contacts MailPoet Vitals tab + */ + private function generate_mailpoet_tab_html( $object_id = -1, $contact = array() ) { - // MailPoet Info - if ( $zbs->mailpoet_is_active() ){ - $array[] = array( - 'id' => 'mailpoet-tab', - 'name' => __( 'MailPoet', 'zero-bs-crm' ), - 'content' => $this->generate_mailpoet_tab_html( $id, $contact ), - ); - } + global $zbs; + // return html + $html = ''; - return $array; + // retrieve lists - we can do this either by checking the current email against mailpoet (as below) + // ... or we could use $contact['external_sources']['mailpoet'][0]['uid'] to call the sub by id + // ... here I've opted for current email, but if we need to we can switch to ^^ - } + // Get just the lists: + // $subscriber_lists = $zbs->modules->mailpoet->get_mailpoet_lists_for_contact_from_email( $contact['email'] ); + // Get all MailPoet subscriber info: + $subscriber = $zbs->modules->mailpoet->get_mailpoet_subscriber_by_email( $contact['email'] ); - /** - * Draw the Contacts MailPoet Vitals tab - */ - private function generate_mailpoet_tab_html( $object_id = -1, $contact = array() ){ + if ( is_array( $subscriber ) ) { - global $zbs; + $html = '
'; - // return html - $html = ''; + // ID + /* + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + */ - // retrieve lists - we can do this either by checking the current email against mailpoet (as below) - // ... or we could use $contact['external_sources']['mailpoet'][0]['uid'] to call the sub by id - // ... here I've opted for current email, but if we need to we can switch to ^^ - - // Get just the lists: - // $subscriber_lists = $zbs->modules->mailpoet->get_mailpoet_lists_for_contact_from_email( $contact['email'] ); - - // Get all MailPoet subscriber info: - $subscriber = $zbs->modules->mailpoet->get_mailpoet_subscriber_by_email( $contact['email'] ); - - if ( is_array( $subscriber ) ){ + // Status + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; - $html = '
ID' . $subscriber['id'] . '
' . __( 'Status', 'zero-bs-crm' ) . '' . ucwords( $subscriber['status'] ) . '
'; + // Email Count + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; - // ID - /* - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - */ + // Lists + $html .= ''; + $html .= ''; + $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; + if ( ! is_array( $subscriber['subscriptions'] ) || count( $subscriber['subscriptions'] ) <= 0 ) { - // Email Count - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; + $html .= '
' . __( 'This contact is not a MailPoet subscriber.', 'zero-bs-crm' ) . '
'; - // Lists - $html .= ''; - $html .= ''; - $html .= ''; + $html .= ''; - } + // Tags + $html .= ''; + $html .= ''; + $html .= ''; - $html .= ''; + if ( ! is_array( $subscriber['tags'] ) || count( $subscriber['tags'] ) <= 0 ) { - // Tags - $html .= ''; - $html .= ''; - $html .= ''; + $html .= ''; - } + $html .= '
' . __( 'Email Count', 'zero-bs-crm' ) . '' . zeroBSCRM_prettifyLongInts( ( isset( $subscriber['email_count'] ) ? $subscriber['email_count'] : 0 ) ) . '
ID' . $subscriber['id'] . '
' . __( 'Lists', 'zero-bs-crm' ) . ''; - // Status - $html .= '
' . __( 'Status', 'zero-bs-crm' ) . '' . ucwords( $subscriber['status'] ) . '
' . __( 'Email Count', 'zero-bs-crm' ) . '' . zeroBSCRM_prettifyLongInts( ( isset( $subscriber['email_count'] ) ? $subscriber['email_count'] : 0 ) ) . '
' . __( 'Lists', 'zero-bs-crm' ) . ''; + } else { - if ( !is_array( $subscriber['subscriptions'] ) || count( $subscriber['subscriptions'] ) <= 0 ){ + $html .= '
'; + $sub_count = 0; - $html .= '
' . __( "This contact is not a MailPoet subscriber.", 'zero-bs-crm' ) . '
'; - - } else { + foreach ( $subscriber['subscriptions'] as $subscription ) { - $html .= '
'; - $sub_count = 0; + if ( $sub_count > 0 ) { - foreach ( $subscriber['subscriptions'] as $subscription ){ + $html .= '
'; - if ( $sub_count > 0 ){ + } - $html .= '
'; + $html .= '' . ( isset( $subscription['segment_name'] ) ? $subscription['segment_name'] : __( 'MailPoet Segment', 'zero-bs-crm' ) ) . ''; - } + ++$sub_count; + } - $html .= '' . ( isset( $subscription['segment_name'] ) ? $subscription['segment_name'] : __( 'MailPoet Segment', 'zero-bs-crm' ) ) . ''; + $html .= '
'; - $sub_count++; - } + } - $html .= '
'; + $html .= '
' . __( 'Tags', 'zero-bs-crm' ) . ''; - $html .= '
' . __( 'Tags', 'zero-bs-crm' ) . ''; + $html .= '
' . __( 'This MailPoet Subscriber does not have any tags.', 'zero-bs-crm' ) . '
'; - if ( !is_array( $subscriber['tags'] ) || count( $subscriber['tags'] ) <= 0 ){ + } else { - $html .= '
' . __( "This MailPoet Subscriber does not have any tags.", 'zero-bs-crm' ) . '
'; - - } else { + foreach ( $subscriber['tags'] as $tag ) { - foreach ( $subscriber['tags'] as $tag ){ + $html .= '' . ( isset( $tag['name'] ) ? $tag['name'] : __( 'Unknown', 'zero-bs-crm' ) ) . ' '; - $html .= '' . ( isset( $tag['name'] ) ? $tag['name'] : __( 'Unknown', 'zero-bs-crm' ) ) . ' '; + } + } - } + $html .= '
'; - $html .= ''; - $html .= ''; - - $html .= ''; + // link + $html .= ''; - // link - $html .= ''; - - - } else { + } else { $html .= '
' . __( 'This contact does not have a MailPoet subscriber.', 'zero-bs-crm' ) . '
'; - - } - return $html; - } + } + + return $html; + } } diff --git a/projects/plugins/crm/modules/mailpoet/includes/jpcrm-mailpoet-default-settings.php b/projects/plugins/crm/modules/mailpoet/includes/jpcrm-mailpoet-default-settings.php index 7f880607f509..876b67b84e54 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/jpcrm-mailpoet-default-settings.php +++ b/projects/plugins/crm/modules/mailpoet/includes/jpcrm-mailpoet-default-settings.php @@ -1,5 +1,5 @@ - 'all', - 'tag_with_list' => '1', // tag contact with mailpoet list(s) - 'tag_with_tags' => '1', // tag contact with mailpoet tag(s) - 'tag_list_prefix' => 'MailPoet List: ', - 'tag_tag_prefix' => 'MailPoet Tag: ', - 'autolog_changes' => '1', - 'delete_action' => 'none', // delete|delete_save_related_objects|add_note|none + 'import_lists' => 'all', + 'tag_with_list' => '1', // tag contact with mailpoet list(s) + 'tag_with_tags' => '1', // tag contact with mailpoet tag(s) + 'tag_list_prefix' => 'MailPoet List: ', + 'tag_tag_prefix' => 'MailPoet Tag: ', + 'autolog_changes' => '1', + 'delete_action' => 'none', // delete|delete_save_related_objects|add_note|none // status management - 'first_import_complete' => false, - 'resume_from_page' => 0, - 'last_subscriber_synced'=> false, + 'first_import_complete' => false, + 'resume_from_page' => 0, + 'last_subscriber_synced' => false, ); diff --git a/projects/plugins/crm/modules/mailpoet/includes/segment-conditions/class-segment-condition-mailpoet-subscriber.php b/projects/plugins/crm/modules/mailpoet/includes/segment-conditions/class-segment-condition-mailpoet-subscriber.php index 14716d595dc8..f74830e5fd09 100644 --- a/projects/plugins/crm/modules/mailpoet/includes/segment-conditions/class-segment-condition-mailpoet-subscriber.php +++ b/projects/plugins/crm/modules/mailpoet/includes/segment-conditions/class-segment-condition-mailpoet-subscriber.php @@ -1,5 +1,5 @@ - 'MailPoet', - 'priority' => 1, - 'operators' => array( 'istrue', 'isfalse' ), - 'fieldname' =>'imported_mailpoet_subscriber' - ); + public $key = 'imported_mailpoet_subscriber'; + public $condition = array( + 'category' => 'MailPoet', + 'priority' => 1, + 'operators' => array( 'istrue', 'isfalse' ), + 'fieldname' => 'imported_mailpoet_subscriber', + ); + /** + * init, here just used to set translated attributes. + */ + public function __construct( $constructionArgs = array() ) { - /** - * init, here just used to set translated attributes. - */ - public function __construct( $constructionArgs = array() ) { + // set translations + $this->condition['name'] = __( 'Imported from MailPoet', 'zero-bs-crm' ); + $this->condition['description'] = __( 'Select contacts which were imported from MailPoet via MailPoet Sync', 'zero-bs-crm' ); - // set translations - $this->condition['name'] = __( 'Imported from MailPoet', 'zero-bs-crm' ); - $this->condition['description'] = __( 'Select contacts which were imported from MailPoet via MailPoet Sync', 'zero-bs-crm' ); + // fire main class init + $this->init( $constructionArgs ); + } + public function conditionArg( $startingArg = false, $condition = false, $conditionKeySuffix = false ) { - // fire main class init - $this->init( $constructionArgs ); + global $zbs, $ZBSCRM_t; - } + if ( $condition['operator'] == 'istrue' ) { + return array( + 'additionalWhereArr' => + array( + 'is_mailpoet_subscriber' . $conditionKeySuffix => array( + 'ID', + 'IN', + '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_CONTACT . ' AND zbss_source = %s)', + array( 'mailpoet' ), + ), + ), + ); + } + if ( $condition['operator'] == 'isfalse' ) { + return array( + 'additionalWhereArr' => + array( + 'is_mailpoet_subscriber' . $conditionKeySuffix => array( + 'ID', + 'NOT IN', + '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_CONTACT . ' AND zbss_source = %s)', + array( 'mailpoet' ), + ), + ), + ); + } - public function conditionArg( $startingArg=false, $condition=false, $conditionKeySuffix=false ){ - - global $zbs, $ZBSCRM_t; - - if ( $condition['operator'] == 'istrue' ) - return array('additionalWhereArr'=> - array( - 'is_mailpoet_subscriber' . $conditionKeySuffix => array( - 'ID','IN', - '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . " WHERE zbss_objtype = ".ZBS_TYPE_CONTACT." AND zbss_source = %s)", - array( 'mailpoet' ) - ) - ) - ); - - if ( $condition['operator'] == 'isfalse' ) - return array('additionalWhereArr'=> - array( - 'is_mailpoet_subscriber' . $conditionKeySuffix => array( - 'ID','NOT IN', - '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . " WHERE zbss_objtype = ".ZBS_TYPE_CONTACT." AND zbss_source = %s)", - array( 'mailpoet' ) - ) - ) - ); - - return $startingArg; - } + return $startingArg; + } } diff --git a/projects/plugins/crm/modules/mailpoet/jpcrm-mailpoet-init.php b/projects/plugins/crm/modules/mailpoet/jpcrm-mailpoet-init.php index a6bef5b69848..c19566e323e6 100644 --- a/projects/plugins/crm/modules/mailpoet/jpcrm-mailpoet-init.php +++ b/projects/plugins/crm/modules/mailpoet/jpcrm-mailpoet-init.php @@ -1,5 +1,5 @@ - 'MailPoet Sync', - 'imgstr' => '', - 'desc' => __( 'Automatically import MailPoet data into your CRM.', 'zero-bs-crm' ), - 'url' => $zbs->urls['mailpoet'], - 'colour' => '#fe5300', - 'helpurl' => $zbs->urls['kb-mailpoet'], - 'shortname' => 'MailPoet', + 'fallbackname' => 'MailPoet Sync', + 'imgstr' => '', + 'desc' => __( 'Automatically import MailPoet data into your CRM.', 'zero-bs-crm' ), + 'url' => $zbs->urls['mailpoet'], + 'colour' => '#fe5300', + 'helpurl' => $zbs->urls['kb-mailpoet'], + 'shortname' => 'MailPoet', ); global $jpcrm_core_extension_setting_map; $jpcrm_core_extension_setting_map['mailpoet'] = 'feat_mailpoet'; - // registers MailPoet Sync as a core extension, and adds to $zeroBSCRM_extensionsCompleteList global function jpcrm_register_free_extension_mailpoet( $exts ) { - // append our module - $exts['mailpoet'] = array( - 'name' => 'MailPoet Sync', - 'i' => 'ext/mailpoet.png', - 'short_desc' => __( 'Automatically import MailPoet data into your CRM.', 'zero-bs-crm' ) - ); - - return $exts; + // append our module + $exts['mailpoet'] = array( + 'name' => 'MailPoet Sync', + 'i' => 'ext/mailpoet.png', + 'short_desc' => __( 'Automatically import MailPoet data into your CRM.', 'zero-bs-crm' ), + ); + return $exts; } add_filter( 'jpcrm_register_free_extensions', 'jpcrm_register_free_extension_mailpoet' ); - // load the Mailpoet class if feature is enabled function jpcrm_load_mailpoet() { - global $zbs; + global $zbs; - // load - if ( zeroBSCRM_isExtensionInstalled( 'mailpoet' ) ) { - - require_once( JPCRM_MODULES_PATH . 'mailpoet/includes/class-mailpoet.php' ); - $zbs->modules->load_module( 'mailpoet', 'Mailpoet' ); + // load + if ( zeroBSCRM_isExtensionInstalled( 'mailpoet' ) ) { - } + require_once JPCRM_MODULES_PATH . 'mailpoet/includes/class-mailpoet.php'; + $zbs->modules->load_module( 'mailpoet', 'Mailpoet' ); + } } add_action( 'jpcrm_load_modules', 'jpcrm_load_mailpoet' ); - // registers MailPoet as an external source function jpcrm_register_external_sources_mailpoet( $external_sources ) { - $external_sources['mailpoet'] = array( - 'MailPoet', - 'ico' => 'fa-users' - ); - return $external_sources; + $external_sources['mailpoet'] = array( + 'MailPoet', + 'ico' => 'fa-users', + ); + return $external_sources; } add_filter( 'jpcrm_register_external_sources', 'jpcrm_register_external_sources_mailpoet' ); - // Install function function zeroBSCRM_extension_install_mailpoet() { - - return jpcrm_install_core_extension( 'mailpoet' ); + return jpcrm_install_core_extension( 'mailpoet' ); } // Uninstall function @@ -86,29 +78,27 @@ function zeroBSCRM_extension_uninstall_mailpoet() { wp_clear_scheduled_hook( 'jpcrm_mailpoet_sync' ); return jpcrm_uninstall_core_extension( 'mailpoet' ); - } // Sniffs for MailPoet, and puts out notification when we have MailPoet but no MailPoet Sync function jpcrm_sniff_feature_mailpoet() { - global $zbs; - - // where we've not got MailPoet active.. - if ( !zeroBSCRM_isExtensionInstalled( 'mailpoet' ) ) { - - // check if MailPoet _is_ active & prompt - $zbs->feature_sniffer->sniff_for_plugin( - array( - 'feature_slug' => 'mailpoet', - 'plugin_slug' => 'mailpoet/mailpoet.php', - 'more_info_link' => $zbs->urls['kb-mailpoet'], - 'is_module' => true, - ) - ); + global $zbs; - } + // where we've not got MailPoet active.. + if ( ! zeroBSCRM_isExtensionInstalled( 'mailpoet' ) ) { + + // check if MailPoet _is_ active & prompt + $zbs->feature_sniffer->sniff_for_plugin( + array( + 'feature_slug' => 'mailpoet', + 'plugin_slug' => 'mailpoet/mailpoet.php', + 'more_info_link' => $zbs->urls['kb-mailpoet'], + 'is_module' => true, + ) + ); + } } add_action( 'jpcrm_sniff_features', 'jpcrm_sniff_feature_mailpoet' ); @@ -148,17 +138,15 @@ function jpcrm_add_mailpoet_jobs_to_system_assistant( $job_list ) { ); } - } return $job_list; - } add_filter( 'jpcrm_system_assistant_jobs', 'jpcrm_add_mailpoet_jobs_to_system_assistant' ); // Extension legacy definitions if ( ! defined( 'JPCRM_MAILPOET_ROOT_FILE' ) ) { - define( 'JPCRM_MAILPOET_ROOT_FILE', __FILE__ ); - define( 'JPCRM_MAILPOET_ROOT_PATH', plugin_dir_path( __FILE__ ) ); - define( 'JPCRM_MAILPOET_IMAGE_URL', plugin_dir_url( JPCRM_MAILPOET_ROOT_FILE ) . 'i/' ); + define( 'JPCRM_MAILPOET_ROOT_FILE', __FILE__ ); + define( 'JPCRM_MAILPOET_ROOT_PATH', plugin_dir_path( __FILE__ ) ); + define( 'JPCRM_MAILPOET_IMAGE_URL', plugin_dir_url( JPCRM_MAILPOET_ROOT_FILE ) . 'i/' ); } diff --git a/projects/plugins/crm/modules/portal/class-client-portal-endpoint.php b/projects/plugins/crm/modules/portal/class-client-portal-endpoint.php index c53efa406cd4..f0073b4d63da 100644 --- a/projects/plugins/crm/modules/portal/class-client-portal-endpoint.php +++ b/projects/plugins/crm/modules/portal/class-client-portal-endpoint.php @@ -1,5 +1,5 @@ should_check_user_permission ) { if ( ! is_user_logged_in() ) { - return $this->portal->get_template('login.php'); + return $this->portal->get_template( 'login.php' ); } if ( ! $this->portal->is_user_enabled() ) { - return $this->portal->get_template('disabled.php'); + return $this->portal->get_template( 'disabled.php' ); } } @@ -66,11 +66,11 @@ public function perform_endpoint_action() { } public function output_html() { - if ($this->template_name != '') { - $this->portal->get_template( + if ( $this->template_name != '' ) { + $this->portal->get_template( $this->template_name, - $this->template_args, - $this->template_path, + $this->template_args, + $this->template_path, $this->default_template_path ); } @@ -79,21 +79,21 @@ public function output_html() { /** * This action gets called before any action (even permission checks) * are performed by this endpoint. - */ + */ public function before_endpoint_actions() { // Do nothing. Should be overwritten by child classes if needed. } /** * This action gets called before any rendering is made by the endpoint. - */ + */ public function pre_content_action() { // Do nothing. Should be overwritten by child classes if needed. } /** * This action gets called after all rendering is finished. - */ + */ public function post_content_action() { // Do nothing. Should be overwritten by child classes if needed. } diff --git a/projects/plugins/crm/modules/portal/class-client-portal-render-helper.php b/projects/plugins/crm/modules/portal/class-client-portal-render-helper.php index f8444d494b8b..cf796fb3635f 100644 --- a/projects/plugins/crm/modules/portal/class-client-portal-render-helper.php +++ b/projects/plugins/crm/modules/portal/class-client-portal-render-helper.php @@ -1,5 +1,5 @@ parent_portal = $parent; } /** - * Shows an object load error and dies. - */ + * Shows an object load error and dies. + */ function show_single_obj_error_and_die() { - $err = '
'; - $err .= '

'.__('Error loading object','zero-bs-crm').'

'; - $err .= __('Either this object does not exist or you do not have permission to view it.', 'zero-bs-crm'); + $err = '
'; + $err .= '

' . __( 'Error loading object', 'zero-bs-crm' ) . '

'; + $err .= __( 'Either this object does not exist or you do not have permission to view it.', 'zero-bs-crm' ); $err .= '
'; echo $err; die( 0 ); @@ -79,18 +78,18 @@ function portal_viewing_as_admin_banner( $admin_message = '' ) {
+ ##WLREMOVE + ?> - '; @@ -122,18 +121,18 @@ function portal_nav( $selected_item = 'dashboard', $do_echo = true ) { } $link = $endpoint->slug == 'dashboard' ? esc_url( $portal_root_url ) : esc_url( $portal_root_url . $endpoint->slug ); $class = $endpoint->slug == $selected_item ? 'active' : ''; - //produce the menu from the array of menu items (easier to extend :-) ). + // produce the menu from the array of menu items (easier to extend :-) ). // WH: this assumes icon, otehrwise it'll break! :o - $nav_html .= "
  • " . $endpoint->name . "
  • "; + $nav_html .= "
  • " . $endpoint->name . '
  • '; } - $zbs_logout_text = __('Log out',"zero-bs-crm"); - $zbs_logout_text = apply_filters('zbs_portal_logout_text', $zbs_logout_text); + $zbs_logout_text = __( 'Log out', 'zero-bs-crm' ); + $zbs_logout_text = apply_filters( 'zbs_portal_logout_text', $zbs_logout_text ); $zbs_logout_icon = 'fa-sign-out'; - $zbs_logout_icon = apply_filters('zbs_portal_logout_icon', $zbs_logout_icon); + $zbs_logout_icon = apply_filters( 'zbs_portal_logout_icon', $zbs_logout_icon ); - $nav_html .= "
  • " . $zbs_logout_text . "
  • "; + $nav_html .= "
  • " . $zbs_logout_text . '
  • '; $nav_html .= ''; // echo or return nav HTML depending on flag; defaults to echo (legacy support) diff --git a/projects/plugins/crm/modules/portal/class-client-portal.php b/projects/plugins/crm/modules/portal/class-client-portal.php index 3e3e46042b8e..0b3e921b1a6c 100644 --- a/projects/plugins/crm/modules/portal/class-client-portal.php +++ b/projects/plugins/crm/modules/portal/class-client-portal.php @@ -1,5 +1,5 @@ endpoints = $endpoint_class::register_endpoint($this->endpoints, $this); + $this->endpoints = $endpoint_class::register_endpoint( $this->endpoints, $this ); } } public function sort_endpoints_by_menu_order() { // Sort all endpoints by their order - usort ( $this->endpoints, function( $endpoint_a, $endpoint_b ) { - if ( $endpoint_a->menu_order == $endpoint_b->menu_order ) { - return 0; - } else { - return ( $endpoint_a->menu_order < $endpoint_b->menu_order ) ? -1 : 1; + usort( + $this->endpoints, + function ( $endpoint_a, $endpoint_b ) { + if ( $endpoint_a->menu_order == $endpoint_b->menu_order ) { + return 0; + } else { + return ( $endpoint_a->menu_order < $endpoint_b->menu_order ) ? -1 : 1; + } } - } ); + ); } /** @@ -112,7 +113,6 @@ public function init_endpoints() { /** * Sorts out the stylesheet includes. - * */ function portal_enqueue_scripts_and_styles() { global $zbs; @@ -121,9 +121,9 @@ function portal_enqueue_scripts_and_styles() { wp_enqueue_style( 'zbs-fa', ZEROBSCRM_URL . 'build/lib/font-awesome/css/font-awesome.min.css', array(), $zbs::VERSION ); // This do_action call was left here for compatibility purposes (legacy). - do_action('zbs_enqueue_portal', 'zeroBS_portal_enqueue_stuff'); + do_action( 'zbs_enqueue_portal', 'zeroBS_portal_enqueue_stuff' ); // This new action should be used for newer implementations. - do_action('jpcrm_enqueue_client_portal_styles'); + do_action( 'jpcrm_enqueue_client_portal_styles' ); } /** @@ -132,9 +132,9 @@ function portal_enqueue_scripts_and_styles() { function portal_theme_support( $classes = array() ) { $theme_slug = get_stylesheet(); - switch( $theme_slug ) { + switch ( $theme_slug ) { case 'twentyseventeen': - $classes[] ='zbs-theme-support-2017'; + $classes[] = 'zbs-theme-support-2017'; break; case 'twentynineteen': $classes[] = 'zbs-theme-support-2019'; @@ -153,21 +153,21 @@ function portal_theme_support( $classes = array() ) { } /** - * Locate template. - * - * Locate the called template. - * Search Order: - * 1. /themes/theme/zerobscrm-plugin-templates/$template_name - * 2. /themes/theme/$template_name - * 3. /plugins/portal/v3/templates/$template_name. - * - * @since 1.2.7 - * - * @param string $template_name Template to load. - * @param string $string $template_path Path to templates. - * @param string $default_path Default path to template files. - * @return string Path to the template file. - */ + * Locate template. + * + * Locate the called template. + * Search Order: + * 1. /themes/theme/zerobscrm-plugin-templates/$template_name + * 2. /themes/theme/$template_name + * 3. /plugins/portal/v3/templates/$template_name. + * + * @since 1.2.7 + * + * @param string $template_name Template to load. + * @param string $string $template_path Path to templates. + * @param string $default_path Default path to template files. + * @return string Path to the template file. + */ function locate_template( $template_name, $template_path = '', $default_path = '' ) { // Set variable to search in zerobscrm-plugin-templates folder of theme. if ( ! $template_path ) : @@ -178,10 +178,12 @@ function locate_template( $template_name, $template_path = '', $default_path = ' $default_path = ZEROBSCRM_PATH . 'modules/portal/templates/'; // Path to the template folder endif; // Search template file in theme folder. - $template = locate_template( array( - $template_path . $template_name, - $template_name - ) ); + $template = locate_template( + array( + $template_path . $template_name, + $template_name, + ) + ); // Get plugins template file. if ( ! $template ) : $template = $default_path . $template_name; @@ -190,24 +192,24 @@ function locate_template( $template_name, $template_path = '', $default_path = ' } /** - * Get template. - * - * Search for the template and include the file. - * - * @since 1.2.7 - * - * @see get_template() - * - * @param string $template_name Template to load. - * @param array $args Args passed for the template file. - * @param string $string $template_path Path to templates. - * @param string $default_path Default path to template files. - */ + * Get template. + * + * Search for the template and include the file. + * + * @since 1.2.7 + * + * @see get_template() + * + * @param string $template_name Template to load. + * @param array $args Args passed for the template file. + * @param string $string $template_path Path to templates. + * @param string $default_path Default path to template files. + */ function get_template( $template_name, $args = array(), $tempate_path = '', $default_path = '' ) { if ( is_array( $args ) && isset( $args ) ) : extract( $args ); - endif; + endif; $template_file = $this->locate_template( $template_name, $tempate_path, $default_path ); if ( ! file_exists( $template_file ) ) : _doing_it_wrong( __FUNCTION__, sprintf( '%s does not exist.', esc_html( $template_file ) ), '1.0.0' ); @@ -218,7 +220,7 @@ function get_template( $template_name, $args = array(), $tempate_path = '', $def // this handles contact detail updates via $_POST from the client portal // this is a #backward-compatibility landmine; proceed with caution (see gh-1642) - function jpcrm_portal_update_details_from_post($cID=-1 ){ + function jpcrm_portal_update_details_from_post( $cID = -1 ) { global $zbs, $zbsCustomerFields; @@ -232,26 +234,26 @@ function jpcrm_portal_update_details_from_post($cID=-1 ){ * - not sure what this is: $zbs->settings->get('fieldhides') */ $hidden_fields = $zbs->settings->get( 'portal_hidefields' ); - $hidden_fields = !empty( $hidden_fields ) ? explode( ',', $hidden_fields ) : array(); + $hidden_fields = ! empty( $hidden_fields ) ? explode( ',', $hidden_fields ) : array(); $read_only_fields = $zbs->settings->get( 'portal_readonlyfields' ); - $read_only_fields = !empty( $read_only_fields ) ? explode( ',', $read_only_fields ) : array(); + $read_only_fields = ! empty( $read_only_fields ) ? explode( ',', $read_only_fields ) : array(); // get existing contact data $old_contact_data = $zbs->DAL->contacts->getContact( $cID ); // downgrade to old-style second address keys so that field names match the object generated by zeroBS_buildContactMeta() $key_map = array( - 'secaddr_addr1' => 'secaddr1', - 'secaddr_addr2' => 'secaddr2', - 'secaddr_city' => 'seccity', - 'secaddr_county' => 'seccounty', - 'secaddr_country' => 'seccountry', - 'secaddr_postcode' => 'secpostcode' + 'secaddr_addr1' => 'secaddr1', + 'secaddr_addr2' => 'secaddr2', + 'secaddr_city' => 'seccity', + 'secaddr_county' => 'seccounty', + 'secaddr_country' => 'seccountry', + 'secaddr_postcode' => 'secpostcode', ); foreach ( $key_map as $newstyle_key => $oldstyle_key ) { - if ( isset( $old_contact_data[$newstyle_key] ) ){ - $old_contact_data[$oldstyle_key] = $old_contact_data[$newstyle_key]; - unset($old_contact_data[$newstyle_key]); + if ( isset( $old_contact_data[ $newstyle_key ] ) ) { + $old_contact_data[ $oldstyle_key ] = $old_contact_data[ $newstyle_key ]; + unset( $old_contact_data[ $newstyle_key ] ); } } @@ -263,21 +265,21 @@ function jpcrm_portal_update_details_from_post($cID=-1 ){ foreach ( $new_contact_data as $key => $value ) { // check for hidden or read only field groups $is_hidden_or_readonly_field_group = false; - if ( isset( $zbsCustomerFields[$key] ) && isset( $zbsCustomerFields[$key]['area'] ) ) { - $area_key = ( $zbsCustomerFields[$key]['area'] == "Main Address" ) ? 'jpcrm-main-address' : ''; - $area_key = ( $zbsCustomerFields[$key]['area'] == "Second Address" ) ? 'jpcrm-main-address' : $area_key; + if ( isset( $zbsCustomerFields[ $key ] ) && isset( $zbsCustomerFields[ $key ]['area'] ) ) { + $area_key = ( $zbsCustomerFields[ $key ]['area'] == 'Main Address' ) ? 'jpcrm-main-address' : ''; + $area_key = ( $zbsCustomerFields[ $key ]['area'] == 'Second Address' ) ? 'jpcrm-main-address' : $area_key; if ( in_array( $area_key, $hidden_fields ) || in_array( $area_key, $read_only_fields ) ) { $is_hidden_or_readonly_field_group = true; } } // if invalid or unauthorised field, keep old value - if ( !isset( $zbsCustomerFields[$key] ) || in_array( $key, $hidden_fields ) || in_array( $key, $read_only_fields) || $is_hidden_or_readonly_field_group ) { - $new_contact_data[$key] = $old_contact_data[$key]; + if ( ! isset( $zbsCustomerFields[ $key ] ) || in_array( $key, $hidden_fields ) || in_array( $key, $read_only_fields ) || $is_hidden_or_readonly_field_group ) { + $new_contact_data[ $key ] = $old_contact_data[ $key ]; } // collect fields that changed - elseif ( $old_contact_data[$key] != $value ) { + elseif ( $old_contact_data[ $key ] != $value ) { $fields_to_change[] = $key; } } @@ -286,23 +288,22 @@ function jpcrm_portal_update_details_from_post($cID=-1 ){ $cID = $zbs->DAL->contacts->addUpdateContact( array( - 'id' => $cID, - 'data' => $new_contact_data, - 'do_not_update_blanks' => false + 'id' => $cID, + 'data' => $new_contact_data, + 'do_not_update_blanks' => false, ) ); - // update log if contact update was successful - if ( $cID ){ + if ( $cID ) { // build long description string for log $longDesc = ''; foreach ( $fields_to_change as $field ) { - if ( !empty( $longDesc ) ) { + if ( ! empty( $longDesc ) ) { $longDesc .= '
    '; } - $longDesc .= sprintf( '%s: %s%s', $field, $old_contact_data[$field], $new_contact_data[$field]); + $longDesc .= sprintf( '%s: %s%s', $field, $old_contact_data[ $field ], $new_contact_data[ $field ] ); } zeroBS_addUpdateLog( @@ -310,18 +311,17 @@ function jpcrm_portal_update_details_from_post($cID=-1 ){ -1, -1, array( - 'type' => __( 'Details updated via Client Portal', 'zero-bs-crm' ), + 'type' => __( 'Details updated via Client Portal', 'zero-bs-crm' ), 'shortdesc' => __( 'Contact changed some of their details via the Client Portal', 'zero-bs-crm' ), - 'longdesc' => $longDesc, + 'longdesc' => $longDesc, ), 'zerobs_customer' ); - echo "
    " . esc_html__( 'Details updated.', 'zero-bs-crm') . "
    "; + echo "
    " . esc_html__( 'Details updated.', 'zero-bs-crm' ) . '
    '; - } - else { - echo "
    " . esc_html__( 'Error updating details!', 'zero-bs-crm' ) . "
    "; + } else { + echo "
    " . esc_html__( 'Error updating details!', 'zero-bs-crm' ) . '
    '; } } @@ -330,30 +330,36 @@ function jpcrm_portal_update_details_from_post($cID=-1 ){ /** * Checks if a user has "enabled" or "disabled" access. - * + * * @return bool True if the user is enabled in the Client Portal. */ function is_user_enabled() { // cached? - if (defined('ZBS_CURRENT_USER_DISABLED')) return false; + if ( defined( 'ZBS_CURRENT_USER_DISABLED' ) ) { + return false; + } global $wpdb; $uid = get_current_user_id(); - $cID = zeroBS_getCustomerIDFromWPID($uid); + $cID = zeroBS_getCustomerIDFromWPID( $uid ); // these ones definitely work - $uinfo = get_userdata( $uid ); - $potentialEmail = ''; if (isset($uinfo->user_email)) $potentialEmail = $uinfo->user_email; - $cID = zeroBS_getCustomerIDWithEmail($potentialEmail); + $uinfo = get_userdata( $uid ); + $potentialEmail = ''; + if ( isset( $uinfo->user_email ) ) { + $potentialEmail = $uinfo->user_email; + } + $cID = zeroBS_getCustomerIDWithEmail( $potentialEmail ); - $disabled = zeroBSCRM_isCustomerPortalDisabled($cID); + $disabled = zeroBSCRM_isCustomerPortalDisabled( $cID ); - if (!$disabled) return true; + if ( ! $disabled ) { + return true; + } // cache to avoid multi-check - define('ZBS_CURRENT_USER_DISABLED',true); + define( 'ZBS_CURRENT_USER_DISABLED', true ); return false; - } /** @@ -407,9 +413,9 @@ function get_portal_query_vars( $vars ) { /** * Lets us check early on in the action stack to see if page is ours. * Only works after 'wp' in action order (needs wp_query->query_var) - * Is also used by zeroBSCRM_isClientPortalPage in Admin Checks + * Is also used by zeroBSCRM_isClientPortalPage in Admin Checks * (which affects force redirect to dash, so be careful). - * + * * @return bool Returns true if the current page is a portal page. */ function is_portal_page() { @@ -422,43 +428,43 @@ function is_portal_page() { * @return bool Returns true if is a child, or a child of a child, of the client portal main page. */ function is_child_of_portal_page() { - global $post; - - if (!is_admin() && function_exists('zeroBSCRM_getSetting') && zeroBSCRM_isExtensionInstalled('portal')){ + global $post; + + if ( ! is_admin() && function_exists( 'zeroBSCRM_getSetting' ) && zeroBSCRM_isExtensionInstalled( 'portal' ) ) { - $portalPage = (int)zeroBSCRM_getSetting('portalpage'); - - if ($portalPage > 0 && isset($post) && is_object($post)){ + $portalPage = (int) zeroBSCRM_getSetting( 'portalpage' ); - if ( is_page() && ($post->post_parent == $portalPage) ) { + if ( $portalPage > 0 && isset( $post ) && is_object( $post ) ) { + + if ( is_page() && ( $post->post_parent == $portalPage ) ) { return true; - } else { + } else { // check 1 level deeper - if ($post->post_parent > 0){ + if ( $post->post_parent > 0 ) { - $parentsParentID = (int)wp_get_post_parent_id($post->post_parent); - - if ($parentsParentID > 0 && ($parentsParentID == $portalPage) ) return true; + $parentsParentID = (int) wp_get_post_parent_id( $post->post_parent ); + if ( $parentsParentID > 0 && ( $parentsParentID == $portalPage ) ) { + return true; + } } - return false; + return false; } } } return false; - } - + /** * Only works after 'wp' in action order (needs $wp_query->post). * - * @return bool If current page loaded has an endpoint that matches ours returns true. False otherwise. + * @return bool If current page loaded has an endpoint that matches ours returns true. False otherwise. */ function is_a_client_portal_endpoint() { global $wp_query; // We get the post id (which will be the page id) + compare to our setting. - $portalPage = zeroBSCRM_getSetting('portalpage'); + $portalPage = zeroBSCRM_getSetting( 'portalpage' ); if ( ! empty( $portalPage ) && $portalPage > 0 && @@ -474,8 +480,7 @@ function is_a_client_portal_endpoint() { } /** - * This is the shortcode function for the Client Portal. - * + * This is the shortcode function for the Client Portal. */ function client_portal_shortcode() { // This function is being called by a shortcode (add_shortcode) and should never return any output (e.g. echo). @@ -485,21 +490,21 @@ function client_portal_shortcode() { // ... a necessary step, because the editor (wp) now runs the shortcode on loading (probs gutenberg) // ... and because this should RETURN, instead it ECHO's directly // ... it should not run on admin side, because that means is probs an edit page! - if ( !is_admin() ) { + if ( ! is_admin() ) { global $wp_query; // Setting the default endpoint to be the dashboard. // This could be customizable by the user if we want to. - $endpoints_slug_array_column = array_column($this->endpoints, null, 'slug'); + $endpoints_slug_array_column = array_column( $this->endpoints, null, 'slug' ); // Let the default endpoint to be overriden by plugins. $default_endpoint_slug = apply_filters( 'jpcrm_client_portal_default_endpoint_slug', 'dashboard', $this ); - $endpoint = $endpoints_slug_array_column[$default_endpoint_slug]; - $portal_query_vars = $this->get_portal_query_vars( $wp_query->query_vars ); + $endpoint = $endpoints_slug_array_column[ $default_endpoint_slug ]; + $portal_query_vars = $this->get_portal_query_vars( $wp_query->query_vars ); - foreach( $portal_query_vars as $var_key => $var_value ) { + foreach ( $portal_query_vars as $var_key => $var_value ) { foreach ( $this->endpoints as $endpoint_search ) { if ( $endpoint_search->slug === $var_key ) { - $endpoint = $endpoint_search; + $endpoint = $endpoint_search; $endpoint->param_value = $var_value; break 2; // Breaks this loop and the outer loop, hence 2. } @@ -519,17 +524,16 @@ function client_portal_shortcode() { /** * This catches failed logins, checks if from our page, then redirs * From mr pippin https://pippinsplugins.com/redirect-to-custom-login-page-on-failed-login/ - * */ function portal_login_fail_redirect( $username ) { $referrer = ''; - if(array_key_exists('HTTP_REFERER', $_SERVER)){ + if ( array_key_exists( 'HTTP_REFERER', $_SERVER ) ) { $referrer = $_SERVER['HTTP_REFERER']; // where did the post submission come from? } // if there's a valid referrer, and it's not the default log-in screen + it's got our post - if ( !empty($referrer) && !strstr($referrer,'wp-login') && !strstr($referrer,'wp-admin') && isset($_POST['fromzbslogin'])) { - wp_redirect(zeroBS_portal_link('dash') . '?login=failed' ); // let's append some information (login=failed) to the URL for the theme to use + if ( ! empty( $referrer ) && ! strstr( $referrer, 'wp-login' ) && ! strstr( $referrer, 'wp-admin' ) && isset( $_POST['fromzbslogin'] ) ) { + wp_redirect( zeroBS_portal_link( 'dash' ) . '?login=failed' ); // let's append some information (login=failed) to the URL for the theme to use exit( 0 ); } } @@ -546,11 +550,11 @@ function get_endpoint( $obj_type_id ) { } /** - * Returns bool if current portal access is provided via easy-access hash - * - * @return bool - true if current access is via hash - */ - function access_is_via_hash( $obj_type_id ){ + * Returns bool if current portal access is provided via easy-access hash + * + * @return bool - true if current access is via hash + */ + function access_is_via_hash( $obj_type_id ) { return $this->router->access_is_via_hash( $obj_type_id ); } @@ -563,5 +567,5 @@ function access_is_via_hash( $obj_type_id ){ */ function get_obj_id_from_current_portal_page_url( $obj_type_id ) { return $this->router->get_obj_id_from_current_portal_page_url( $obj_type_id ); - } + } } diff --git a/projects/plugins/crm/modules/portal/endpoints/class-details-endpoint.php b/projects/plugins/crm/modules/portal/endpoints/class-details-endpoint.php index d09384cf370c..726901264d38 100644 --- a/projects/plugins/crm/modules/portal/endpoints/class-details-endpoint.php +++ b/projects/plugins/crm/modules/portal/endpoints/class-details-endpoint.php @@ -32,26 +32,26 @@ public function render_admin_notice() { // phpcs:ignore Squiz.Commenting.Functio // Functions that were in the template file public function save_details() { // phpcs:ignore Squiz.Commenting.FunctionComment.WrongStyle - if( + if ( $_POST['save'] == 1 && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'jpcrm-update-client-details' ) ) { - $uid = get_current_user_id(); + $uid = get_current_user_id(); $uinfo = get_userdata( $uid ); - $cID = zeroBS_getCustomerIDWithEmail($uinfo->user_email); + $cID = zeroBS_getCustomerIDWithEmail( $uinfo->user_email ); // added !empty check - because if logged in as admin, saved deets, it made a new contact for them - if((int)$_POST['customer_id'] == $cID && !empty($cID)){ + if ( (int) $_POST['customer_id'] == $cID && ! empty( $cID ) ) { // handle the password fields, if set. - if(isset($_POST['password']) && !empty($_POST['password']) && isset($_POST['password2']) && !empty($_POST['password2']) ){ + if ( isset( $_POST['password'] ) && ! empty( $_POST['password'] ) && isset( $_POST['password2'] ) && ! empty( $_POST['password2'] ) ) { - if($_POST['password'] != $_POST['password2']){ - echo "
    " . esc_html__("Passwords do not match","zero-bs-crm") . "
    "; + if ( $_POST['password'] != $_POST['password2'] ) { + echo "
    " . esc_html__( 'Passwords do not match', 'zero-bs-crm' ) . '
    '; } else { // update password - wp_set_password( sanitize_text_field($_POST['password']), $uid); + wp_set_password( sanitize_text_field( $_POST['password'] ), $uid ); // log password change zeroBS_addUpdateLog( @@ -59,62 +59,76 @@ public function save_details() { // phpcs:ignore Squiz.Commenting.FunctionCommen -1, -1, array( - 'type' => __( 'Password updated via Client Portal', 'zero-bs-crm' ), + 'type' => __( 'Password updated via Client Portal', 'zero-bs-crm' ), 'shortdesc' => __( 'Contact changed their password via the Client Portal', 'zero-bs-crm' ), - 'longdesc' => '', + 'longdesc' => '', ), 'zerobs_customer' ); // display message - echo "
    " . esc_html__( 'Password updated.', 'zero-bs-crm' ) . "
    "; + echo "
    " . esc_html__( 'Password updated.', 'zero-bs-crm' ) . '
    '; // update any details as well - $this->portal->jpcrm_portal_update_details_from_post($cID); + $this->portal->jpcrm_portal_update_details_from_post( $cID ); } } else { // update any details as well - $this->portal->jpcrm_portal_update_details_from_post($cID); + $this->portal->jpcrm_portal_update_details_from_post( $cID ); } - do_action('jpcrm_client_portal_after_save_details'); + do_action( 'jpcrm_client_portal_after_save_details' ); } } - } + } function get_value( $fieldK, $zbsCustomer ) { // get a value (this allows field-irrelevant global tweaks, like the addr catch below...) $value = ''; - if (isset($zbsCustomer[$fieldK])) $value = $zbsCustomer[$fieldK]; + if ( isset( $zbsCustomer[ $fieldK ] ) ) { + $value = $zbsCustomer[ $fieldK ]; + } // #backward-compatibility // 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 ($fieldK){ + switch ( $fieldK ) { case 'secaddr1': - if (isset($zbsCustomer['secaddr_addr1'])) $value = $zbsCustomer['secaddr_addr1']; + if ( isset( $zbsCustomer['secaddr_addr1'] ) ) { + $value = $zbsCustomer['secaddr_addr1']; + } break; case 'secaddr2': - if (isset($zbsCustomer['secaddr_addr2'])) $value = $zbsCustomer['secaddr_addr2']; + if ( isset( $zbsCustomer['secaddr_addr2'] ) ) { + $value = $zbsCustomer['secaddr_addr2']; + } break; case 'seccity': - if (isset($zbsCustomer['secaddr_city'])) $value = $zbsCustomer['secaddr_city']; + if ( isset( $zbsCustomer['secaddr_city'] ) ) { + $value = $zbsCustomer['secaddr_city']; + } break; case 'seccounty': - if (isset($zbsCustomer['secaddr_county'])) $value = $zbsCustomer['secaddr_county']; + if ( isset( $zbsCustomer['secaddr_county'] ) ) { + $value = $zbsCustomer['secaddr_county']; + } break; case 'seccountry': - if (isset($zbsCustomer['secaddr_country'])) $value = $zbsCustomer['secaddr_country']; + if ( isset( $zbsCustomer['secaddr_country'] ) ) { + $value = $zbsCustomer['secaddr_country']; + } break; case 'secpostcode': - if (isset($zbsCustomer['secaddr_postcode'])) $value = $zbsCustomer['secaddr_postcode']; + if ( isset( $zbsCustomer['secaddr_postcode'] ) ) { + $value = $zbsCustomer['secaddr_postcode']; + } break; } @@ -122,8 +136,8 @@ function get_value( $fieldK, $zbsCustomer ) { } function render_text_field( $fieldK, $fieldV, $value ) { - $extra_attributes = ""; - if ( isset( $fieldV[ 'read_only' ] ) && $fieldV[ 'read_only' ] ) { + $extra_attributes = ''; + if ( isset( $fieldV['read_only'] ) && $fieldV['read_only'] ) { $extra_attributes .= ' readonly disabled '; } ?> @@ -134,15 +148,17 @@ function render_text_field( $fieldK, $fieldV, $value ) {

    - + ?> +

    + style="width: 130px;display: inline-block;;" type="text" name="zbsc_" id="" class="form-control numbersOnly" placeholder="" value="" autocomplete="" /> -

    + @@ -186,43 +202,50 @@ function render_date_field( $field_key, $field_value, $value ) {

    - + @@ -231,30 +254,36 @@ function render_select_field($fieldK, $fieldV, $value){

    - + ?> +

    + type="text" name="zbsc_" id="" class="form-control zbs-tel" placeholder="" value="" autocomplete="" /> - ' . esc_html( $zbsCustomer[$fieldK] ) . ''; ?> ' . esc_html( $zbsCustomer[ $fieldK ] ) . '';} + ?> + '. esc_html__('SMS','zero-bs-crm') . ': ' . esc_html( $customerMob ) . ''; + if ( ! empty( $customerMob ) ) { + echo ' ' . esc_html__( 'SMS', 'zero-bs-crm' ) . ': ' . esc_html( $customerMob ) . ''; + } } ?> @@ -262,18 +291,20 @@ function render_telephone_field($fieldK, $fieldV, $value, $zbsCustomer) {

    - + ?> +

    +

    type="text" name="zbsc_" id="" class="form-control zbs-email" placeholder="" value="" autocomplete="" />
    -

    +

    + ?> +

    -

    +

    - + ?> +

    + -

    +

    - + ?> +

    +

    0 && $options[0] != ''){ + if ( isset( $options ) && is_array( $options ) && count( $options ) > 0 && $options[0] != '' ) { $optIndex = 0; - foreach ($options as $opt){ + foreach ( $options as $opt ) { // echo '
    '; - echo '
    '; - $optIndex++; + ++$optIndex; } - - } else echo '-'; + } else { + echo '-'; + } ?>
    -

    +

    - + ?> +

    +

    0 && $options[0] != ''){ + if ( isset( $options ) && is_array( $options ) && count( $options ) > 0 && $options[0] != '' ) { $optIndex = 0; - foreach ($options as $opt){ + foreach ( $options as $opt ) { echo '
    '; echo '
    '; - $optIndex++; + ++$optIndex; } - - } else echo '-'; + } else { + echo '-'; + } ?>
    -

    + render_country_list_field( $fieldK, $fieldV, $value, $showCountryFields ); + $this->render_country_list_field( $fieldK, $fieldV, $value, $showCountryFields ); break; // 2.98.5 added autonumber, checkbox, radio diff --git a/projects/plugins/crm/modules/portal/endpoints/class-invoices-endpoint.php b/projects/plugins/crm/modules/portal/endpoints/class-invoices-endpoint.php index e4997fa95fcf..e0d4e8f3dd15 100644 --- a/projects/plugins/crm/modules/portal/endpoints/class-invoices-endpoint.php +++ b/projects/plugins/crm/modules/portal/endpoints/class-invoices-endpoint.php @@ -39,33 +39,31 @@ public function before_endpoint_actions() { $this->template_name = 'single-invoice.php'; $this->should_check_user_permission = $zbs->settings->get( 'easyaccesslinks' ) === 0; } - } /** * Single Endpoint rendering function */ function single_invoice_html_output( $invoice_id = -1, $invoice_hash = '' ) { - echo zeroBSCRM_invoice_generatePortalInvoiceHTML( $invoice_id, $invoice_hash ); + echo zeroBSCRM_invoice_generatePortalInvoiceHTML( $invoice_id, $invoice_hash ); } #} New functions here. Used as NAMED in WooSync. Please do not rename and not tell me as need to update WooSync if so - #} 1. The invoice list function + #} 1. The invoice list function /** - * - * @param $link and $endpoint as they will differ between Portal and WooCommerce My Account - * - */ - function list_invoices_html_output($link = '', $endpoint = ''){ + * + * @param $link and $endpoint as they will differ between Portal and WooCommerce My Account + */ + function list_invoices_html_output( $link = '', $endpoint = '' ) { global $wpdb; - $uid = get_current_user_id(); - $uinfo = get_userdata( $uid ); - $cID = zeroBS_getCustomerIDWithEmail($uinfo->user_email); + $uid = get_current_user_id(); + $uinfo = get_userdata( $uid ); + $cID = zeroBS_getCustomerIDWithEmail( $uinfo->user_email ); $is_invoice_admin = $uinfo->has_cap( 'admin_zerobs_invoices' ); // if the current is a valid contact or a WP user with permissions to view invoices... - if( $cID > 0 || $is_invoice_admin ){ + if ( $cID > 0 || $is_invoice_admin ) { // this allows the current admin to see all invoices even if they're a contact if ( $is_invoice_admin ) { @@ -74,84 +72,89 @@ function list_invoices_html_output($link = '', $endpoint = ''){ } // get invoices - $customer_invoices = zeroBS_getInvoicesForCustomer($cID,true,100,0,false); + $customer_invoices = zeroBS_getInvoicesForCustomer( $cID, true, 100, 0, false ); // if there are more than zero invoices... - if(count($customer_invoices) > 0){ + if ( count( $customer_invoices ) > 0 ) { global $zbs; - ?> + '; $idLinkEnd = ''; + $idLinkStart = ''; + $idLinkEnd = ''; + if ( ! empty( $invoiceURL ) ) { + $idLinkStart = ''; + $idLinkEnd = ''; } echo ''; - echo ''. $idLinkStart . esc_html( $idStr ) . ' '. esc_html__('(view)', 'zero-bs-crm') . $idLinkEnd.''; - echo '' . esc_html( $cinv['date_date'] ) . ''; - echo '' . esc_html( $due_date_str ) . ''; - echo '' . esc_html( zeroBSCRM_formatCurrency($cinv['total']) ) . ''; - echo '' . esc_html( $cinv['status'] ) . ''; + echo '' . $idLinkStart . esc_html( $idStr ) . ' ' . esc_html__( '(view)', 'zero-bs-crm' ) . $idLinkEnd . ''; + echo '' . esc_html( $cinv['date_date'] ) . ''; + echo '' . esc_html( $due_date_str ) . ''; + echo '' . esc_html( zeroBSCRM_formatCurrency( $cinv['total'] ) ) . ''; + echo '' . esc_html( $cinv['status'] ) . ''; - do_action('zbs-extra-invoice-body-table', $cinv['id']); + do_action( 'zbs-extra-invoice-body-table', $cinv['id'] ); - // echo ''; + // echo ''; echo ''; } $invoices_to_show = ob_get_contents(); ob_end_clean(); - if ( !empty( $invoices_to_show ) ) { + if ( ! empty( $invoices_to_show ) ) { // there are invoices to show to this user, so build table echo ''; echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - do_action('zbs-extra-invoice-header-table'); + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + do_action( 'zbs-extra-invoice-header-table' ); echo ''; echo $invoices_to_show; echo '
    ' . esc_html( $zbs->settings->get('reflabel') ) . '' . esc_html__('Date','zero-bs-crm') . '' . esc_html__('Due date','zero-bs-crm') . '' . esc_html__('Total','zero-bs-crm') . '' . esc_html__('Status','zero-bs-crm') . '' . esc_html( $zbs->settings->get( 'reflabel' ) ) . '' . esc_html__( 'Date', 'zero-bs-crm' ) . '' . esc_html__( 'Due date', 'zero-bs-crm' ) . '' . esc_html__( 'Total', 'zero-bs-crm' ) . '' . esc_html__( 'Status', 'zero-bs-crm' ) . '
    '; - } - else { + } else { // no invoices to show...might have drafts but no admin perms esc_html_e( 'You do not have any invoices yet.', 'zero-bs-crm' ); } - }else{ + } else { // invoice object count for current user is 0 esc_html_e( 'You do not have any invoices yet.', 'zero-bs-crm' ); } - }else{ + } else { // not a valid contact or invoice admin user esc_html_e( 'You do not have any invoices yet.', 'zero-bs-crm' ); } - } + } } diff --git a/projects/plugins/crm/modules/portal/endpoints/class-single-quote-endpoint.php b/projects/plugins/crm/modules/portal/endpoints/class-single-quote-endpoint.php index ae644a692360..d1f558495398 100644 --- a/projects/plugins/crm/modules/portal/endpoints/class-single-quote-endpoint.php +++ b/projects/plugins/crm/modules/portal/endpoints/class-single-quote-endpoint.php @@ -33,15 +33,15 @@ public static function register_endpoint( $endpoints, $client_portal ) { // phpc * * Previously called zeroBSCRM_quote_generatePortalQuoteHTML */ - function single_quote_html_output( $quote_id = -1, $quote_hash='' ) { + function single_quote_html_output( $quote_id = -1, $quote_hash = '' ) { global $post, $zbs; - $quote_data = zeroBS_getQuote( $quote_id, true ); + $quote_data = zeroBS_getQuote( $quote_id, true ); $quote_content = ''; - $acceptable = false; + $acceptable = false; - if ( !$quote_data ) { + if ( ! $quote_data ) { // something is wrong...abort! $this->show_single_obj_error_and_die(); } @@ -60,7 +60,7 @@ function single_quote_html_output( $quote_id = -1, $quote_hash='' ) { $quote_hash = $quote_data['hash']; } - // acceptable? + // acceptable? if ( empty( $quote_data['accepted'] ) ) { $acceptable = true; } else { @@ -69,7 +69,7 @@ function single_quote_html_output( $quote_id = -1, $quote_hash='' ) { $acceptedDate = $quote_data['accepted_date']; } } -?> + ?>
    acceptable_html ); ?>
    @@ -77,11 +77,11 @@ function single_quote_html_output( $quote_id = -1, $quote_hash='' ) { - '; - - } else { - - $html .= '
    ' . __( "This contact does not have any upcoming WooCommerce Bookings.", 'zero-bs-crm' ) . '
    '; - - } - - return $html; - } - + } + return $html; + } /** * Returns HTML that can be used to render the Subscriptions Table. @@ -190,7 +177,7 @@ private function generate_subscriptions_tab_html( $object_id = -1 ) { return '
    ' . __( 'This contact does not have any WooCommerce Subscriptions yet.', 'zero-bs-crm' ) . '
    '; } - $html = ''; + $html = ''; $html .= '
    '; $html .= ''; $html .= ''; @@ -228,10 +215,8 @@ private function generate_subscriptions_tab_html( $object_id = -1 ) { $html .= ''; return $html; - } - /** * Generate HTML for memberships contact vitals tab */ @@ -242,12 +227,12 @@ private function generate_memberships_tab_html( $object_id = -1 ) { if ( $data['message'] === 'notfound' || count( $data['memberships'] ) <= 0 ) { return '
    ' . __( 'This contact does not have any WooCommerce Memberships yet.', 'zero-bs-crm' ) . '
    '; - + } $memberships = $data['memberships']; - $html = ''; + $html = ''; $html .= '
    '; $html .= '
    '; $html .= ''; @@ -298,59 +283,56 @@ private function generate_memberships_tab_html( $object_id = -1 ) { return $html; } + /** + * Helper to display membership statuses + */ + private function display_membership_status( $status = '' ) { - /** - * Helper to display membership statuses - */ - private function display_membership_status( $status = '' ){ - - $woocommerce_statuses = array( - 'wcm-active' => __('active', 'zero-bs-crm'), - 'wcm-complimentary' => __('complimentary', 'zero-bs-crm'), - 'wcm-pending' => __('pending', 'zero-bs-crm'), - 'wcm-delayed' => __('delayed', 'zero-bs-crm'), - 'wcm-pending-cancelletion' => __('pending cancellation', 'zero-bs-crm'), - 'wcm-paused' => __('paused', 'zero-bs-crm'), - 'wcm-expired' => __('expired', 'zero-bs-crm'), - 'wcm-cancelled' => __('cancelled', 'zero-bs-crm') - ); - - $display_status = $status; - - if ( array_key_exists( $status, $woocommerce_statuses ) ){ + $woocommerce_statuses = array( + 'wcm-active' => __( 'active', 'zero-bs-crm' ), + 'wcm-complimentary' => __( 'complimentary', 'zero-bs-crm' ), + 'wcm-pending' => __( 'pending', 'zero-bs-crm' ), + 'wcm-delayed' => __( 'delayed', 'zero-bs-crm' ), + 'wcm-pending-cancelletion' => __( 'pending cancellation', 'zero-bs-crm' ), + 'wcm-paused' => __( 'paused', 'zero-bs-crm' ), + 'wcm-expired' => __( 'expired', 'zero-bs-crm' ), + 'wcm-cancelled' => __( 'cancelled', 'zero-bs-crm' ), + ); - $display_status = $woocommerce_statuses[$status]; + $display_status = $status; - } + if ( array_key_exists( $status, $woocommerce_statuses ) ) { - return $display_status; + $display_status = $woocommerce_statuses[ $status ]; - } + } + return $display_status; + } - /** - * Retrieves memberships for a contact - */ - private function get_contact_memberships( $object_id = -1 ){ + /** + * Retrieves memberships for a contact + */ + private function get_contact_memberships( $object_id = -1 ) { - $wp_id = zeroBS_getCustomerWPID( $object_id ); + $wp_id = zeroBS_getCustomerWPID( $object_id ); - if ( $wp_id > 0 ){ + if ( $wp_id > 0 ) { - return array( - 'message' => 'success', - 'memberships' => wc_memberships_get_user_memberships( $wp_id ) - ); + return array( + 'message' => 'success', + 'memberships' => wc_memberships_get_user_memberships( $wp_id ), + ); - } else { + } else { - return array( - 'message' => 'notfound', - 'memberships' => array() - ); + return array( + 'message' => 'notfound', + 'memberships' => array(), + ); - } - } + } + } /** * Retrieves any Woo Subscriptions against a contact diff --git a/projects/plugins/crm/modules/woo-sync/includes/jpcrm-woo-sync-default-settings.php b/projects/plugins/crm/modules/woo-sync/includes/jpcrm-woo-sync-default-settings.php index c60e2db14ca7..bfb7e30a7781 100644 --- a/projects/plugins/crm/modules/woo-sync/includes/jpcrm-woo-sync-default-settings.php +++ b/projects/plugins/crm/modules/woo-sync/includes/jpcrm-woo-sync-default-settings.php @@ -1,5 +1,5 @@ - array(), + 'sync_sites' => array(), // 0 = no, 1 = yes - 'wccopyship' => '0', - 'wctagcust' => '1', // tag contacts with item - 'wctagtransaction' => '1', // tag transaction with item - 'wctaginvoice' => '1', // tag invoice with item - 'wctagcoupon' => '1', // Include any passed coupon code as a tag (dependent on above 3 settings) - 'wctagproductprefix' => 'Product: ', - 'wctagcouponprefix' => 'Coupon: ', - 'wcinv' => '0', - 'wcprod' => '0', - 'wcacc' => '1', + 'wccopyship' => '0', + 'wctagcust' => '1', // tag contacts with item + 'wctagtransaction' => '1', // tag transaction with item + 'wctaginvoice' => '1', // tag invoice with item + 'wctagcoupon' => '1', // Include any passed coupon code as a tag (dependent on above 3 settings) + 'wctagproductprefix' => 'Product: ', + 'wctagcouponprefix' => 'Coupon: ', + 'wcinv' => '0', + 'wcprod' => '0', + 'wcacc' => '1', // autodeletion - 'auto_trash' => 'change_status', // do_nothing | change_status | hard_delete_and_log - 'auto_delete' => 'change_status', // do_nothing | change_status | hard_delete_and_log + 'auto_trash' => 'change_status', // do_nothing | change_status | hard_delete_and_log + 'auto_delete' => 'change_status', // do_nothing | change_status | hard_delete_and_log 'enable_woo_status_mapping' => 1, diff --git a/projects/plugins/crm/modules/woo-sync/includes/segment-conditions/class-segment-condition-woo-customer.php b/projects/plugins/crm/modules/woo-sync/includes/segment-conditions/class-segment-condition-woo-customer.php index 364326d40ef0..d6615b266988 100644 --- a/projects/plugins/crm/modules/woo-sync/includes/segment-conditions/class-segment-condition-woo-customer.php +++ b/projects/plugins/crm/modules/woo-sync/includes/segment-conditions/class-segment-condition-woo-customer.php @@ -1,5 +1,5 @@ - 1, - 'category' => 'WooSync', - 'operators' => array( 'istrue', 'isfalse' ), - 'fieldname' =>'is_woo_customer' - ); + public $key = 'is_woo_customer'; + public $condition = array( + 'position' => 1, + 'category' => 'WooSync', + 'operators' => array( 'istrue', 'isfalse' ), + 'fieldname' => 'is_woo_customer', + ); - /** - * init, here just used to set translated attributes. - */ - public function __construct( $constructionArgs = array() ) { + /** + * init, here just used to set translated attributes. + */ + public function __construct( $constructionArgs = array() ) { - // set translations - $this->condition['name'] = __( 'WooCommerce Customer', 'zero-bs-crm' ); - $this->condition['description'] = __( 'Select contacts who are or are not also WooCommerce customers', 'zero-bs-crm' ); + // set translations + $this->condition['name'] = __( 'WooCommerce Customer', 'zero-bs-crm' ); + $this->condition['description'] = __( 'Select contacts who are or are not also WooCommerce customers', 'zero-bs-crm' ); + // fire main class init + $this->init( $constructionArgs ); + } - // fire main class init - $this->init( $constructionArgs ); + public function conditionArg( $startingArg = false, $condition = false, $conditionKeySuffix = false ) { - } + global $zbs, $ZBSCRM_t; - public function conditionArg( $startingArg=false, $condition=false, $conditionKeySuffix=false ){ - - global $zbs, $ZBSCRM_t; - - if ( $condition['operator'] == 'istrue' ) - return array('additionalWhereArr'=> - array( - 'is_woo_customer' . $conditionKeySuffix => array( - 'ID','IN', - '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . " WHERE zbss_objtype = ".ZBS_TYPE_CONTACT." AND zbss_source = %s)", - array( 'woo' ) - ) - ) - ); - - if ( $condition['operator'] == 'isfalse' ) - return array('additionalWhereArr'=> - array( - 'is_woo_customer' . $conditionKeySuffix => array( - 'ID','NOT IN', - '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . " WHERE zbss_objtype = ".ZBS_TYPE_CONTACT." AND zbss_source = %s)", - array( 'woo' ) - ) - ) - ); + if ( $condition['operator'] == 'istrue' ) { + return array( + 'additionalWhereArr' => + array( + 'is_woo_customer' . $conditionKeySuffix => array( + 'ID', + 'IN', + '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_CONTACT . ' AND zbss_source = %s)', + array( 'woo' ), + ), + ), + ); + } - return $startingArg; - } + if ( $condition['operator'] == 'isfalse' ) { + return array( + 'additionalWhereArr' => + array( + 'is_woo_customer' . $conditionKeySuffix => array( + 'ID', + 'NOT IN', + '(SELECT DISTINCT zbss_objid FROM ' . $ZBSCRM_t['externalsources'] . ' WHERE zbss_objtype = ' . ZBS_TYPE_CONTACT . ' AND zbss_source = %s)', + array( 'woo' ), + ), + ), + ); + } + + return $startingArg; + } } diff --git a/projects/plugins/crm/modules/woo-sync/includes/segment-conditions/class-segment-condition-woo-order-count.php b/projects/plugins/crm/modules/woo-sync/includes/segment-conditions/class-segment-condition-woo-order-count.php index d2f0f468942e..19ca9d052370 100644 --- a/projects/plugins/crm/modules/woo-sync/includes/segment-conditions/class-segment-condition-woo-order-count.php +++ b/projects/plugins/crm/modules/woo-sync/includes/segment-conditions/class-segment-condition-woo-order-count.php @@ -1,5 +1,5 @@ - 'WooSync', - 'position' => 2, - 'operators' => array( 'equal', 'notequal', 'larger', 'less', 'intrange', 'largerequal', 'lessequal' ), - 'fieldname' => 'woo_order_count', - 'inputmask' => 'int' - ); + public $key = 'woo_order_count'; + public $condition = array( + 'category' => 'WooSync', + 'position' => 2, + 'operators' => array( 'equal', 'notequal', 'larger', 'less', 'intrange', 'largerequal', 'lessequal' ), + 'fieldname' => 'woo_order_count', + 'inputmask' => 'int', + ); - /** - * init, here just used to set translated attributes. - */ - public function __construct( $constructionArgs = array() ) { + /** + * init, here just used to set translated attributes. + */ + public function __construct( $constructionArgs = array() ) { - // set translations - $this->condition['name'] = __( 'WooCommerce Order Count', 'zero-bs-crm' ); - $this->condition['description'] = __( 'Select contacts who match WooCommerce customers with specific order counts', 'zero-bs-crm' ); + // set translations + $this->condition['name'] = __( 'WooCommerce Order Count', 'zero-bs-crm' ); + $this->condition['description'] = __( 'Select contacts who match WooCommerce customers with specific order counts', 'zero-bs-crm' ); + // fire main class init + $this->init( $constructionArgs ); + } - // fire main class init - $this->init( $constructionArgs ); + public function conditionArg( $startingArg = false, $condition = false, $conditionKeySuffix = false ) { - } + global $zbs, $ZBSCRM_t; - - public function conditionArg( $startingArg=false, $condition=false, $conditionKeySuffix=false ){ - - global $zbs, $ZBSCRM_t; + // here we just count objlinks, which has the vulnerability that if there are orphan links created it'll show wrong count, but for now is 'enough' + // Note this also ignores ownership :O + $order_count_query = 'SELECT COUNT(DISTINCT(obj_links.zbsol_objid_from)) FROM ' . $ZBSCRM_t['objlinks'] . ' obj_links' + . ' INNER JOIN ' . $ZBSCRM_t['externalsources'] . ' ext_sources' + . ' ON obj_links.zbsol_objid_from = ext_sources.zbss_objid' + . ' WHERE obj_links.zbsol_objtype_from = ' . ZBS_TYPE_TRANSACTION + . ' AND obj_links.zbsol_objtype_to = ' . ZBS_TYPE_CONTACT + . ' AND obj_links.zbsol_objid_to = contact.ID' + . ' AND ext_sources.zbss_objtype = ' . ZBS_TYPE_TRANSACTION; - // here we just count objlinks, which has the vulnerability that if there are orphan links created it'll show wrong count, but for now is 'enough' - // Note this also ignores ownership :O - $order_count_query = "SELECT COUNT(DISTINCT(obj_links.zbsol_objid_from)) FROM " . $ZBSCRM_t['objlinks'] . " obj_links" - . " INNER JOIN " . $ZBSCRM_t['externalsources'] . " ext_sources" - . " ON obj_links.zbsol_objid_from = ext_sources.zbss_objid" - . " WHERE obj_links.zbsol_objtype_from = " . ZBS_TYPE_TRANSACTION - . " AND obj_links.zbsol_objtype_to = " . ZBS_TYPE_CONTACT - . " AND obj_links.zbsol_objid_to = contact.ID" - . " AND ext_sources.zbss_objtype = " . ZBS_TYPE_TRANSACTION; - - /* example: - SELECT * FROM - wp_zbs_object_links obj_links - INNER JOIN wp_zbs_externalsources ext_sources - ON obj_links.zbsol_objid_from = ext_sources.zbss_objid - WHERE obj_links.zbsol_objtype_from = 5 - AND obj_links.zbsol_objtype_to = 1 - AND obj_links.zbsol_objid_to = {CONTACTID} - AND ext_sources.zbss_objtype = 5 - */ + /* + example: + SELECT * FROM + wp_zbs_object_links obj_links + INNER JOIN wp_zbs_externalsources ext_sources + ON obj_links.zbsol_objid_from = ext_sources.zbss_objid + WHERE obj_links.zbsol_objtype_from = 5 + AND obj_links.zbsol_objtype_to = 1 + AND obj_links.zbsol_objid_to = {CONTACTID} + AND ext_sources.zbss_objtype = 5 + */ - if ( $condition['operator'] == 'equal' ) - return array('additionalWhereArr'=> - array( - 'woo_order_count_equal' . $conditionKeySuffix => array( - "(" . $order_count_query . ")", - '=', - '%d', - $condition['value'] - ) - ) - ); - else if ( $condition['operator'] == 'notequal' ) - return array('additionalWhereArr'=> - array( - 'woo_order_count_notequal' . $conditionKeySuffix => array( - "(" . $order_count_query . ")", - '<>', - '%d', - $condition['value'] - ) - ) - ); - else if ( $condition['operator'] == 'larger' ) - return array('additionalWhereArr'=> - array( - 'woo_order_count_larger' . $conditionKeySuffix => array( - "(" . $order_count_query . ")", - '>', - '%d', - $condition['value'] - ) - ) - ); - else if ( $condition['operator'] == 'largerequal' ) - return array('additionalWhereArr'=> - array( - 'woo_order_count_larger_equal' . $conditionKeySuffix => array( - "(" . $order_count_query . ")", - '>=', - '%d', - $condition['value'] - ) - ) - ); - else if ( $condition['operator'] == 'less' ) - return array('additionalWhereArr'=> - array( - 'woo_order_count_smaller' . $conditionKeySuffix => array( - "(" . $order_count_query . ")", - '<', - '%d', - $condition['value'] - ) - ) - ); - else if ( $condition['operator'] == 'lessequal' ) - return array('additionalWhereArr'=> - array( - 'woo_order_count_smaller_equal' . $conditionKeySuffix => array( - "(" . $order_count_query . ")", - '<=', - '%d', - $condition['value'] - ) - ) - ); - else if ( $condition['operator'] == 'intrange' ) - return array('additionalWhereArr'=> - array( - 'woo_order_count_larger' . $conditionKeySuffix => array( - "(" . $order_count_query . ")", - '>=', - '%d', - $condition['value'] - ), - 'woo_order_count_smaller' . $conditionKeySuffix => array( - "(" . $order_count_query . ")", - '<=', - '%d', - $condition['value2'] - ) - ) - ); + if ( $condition['operator'] == 'equal' ) { + return array( + 'additionalWhereArr' => + array( + 'woo_order_count_equal' . $conditionKeySuffix => array( + '(' . $order_count_query . ')', + '=', + '%d', + $condition['value'], + ), + ), + ); + } elseif ( $condition['operator'] == 'notequal' ) { + return array( + 'additionalWhereArr' => + array( + 'woo_order_count_notequal' . $conditionKeySuffix => array( + '(' . $order_count_query . ')', + '<>', + '%d', + $condition['value'], + ), + ), + ); + } elseif ( $condition['operator'] == 'larger' ) { + return array( + 'additionalWhereArr' => + array( + 'woo_order_count_larger' . $conditionKeySuffix => array( + '(' . $order_count_query . ')', + '>', + '%d', + $condition['value'], + ), + ), + ); + } elseif ( $condition['operator'] == 'largerequal' ) { + return array( + 'additionalWhereArr' => + array( + 'woo_order_count_larger_equal' . $conditionKeySuffix => array( + '(' . $order_count_query . ')', + '>=', + '%d', + $condition['value'], + ), + ), + ); + } elseif ( $condition['operator'] == 'less' ) { + return array( + 'additionalWhereArr' => + array( + 'woo_order_count_smaller' . $conditionKeySuffix => array( + '(' . $order_count_query . ')', + '<', + '%d', + $condition['value'], + ), + ), + ); + } elseif ( $condition['operator'] == 'lessequal' ) { + return array( + 'additionalWhereArr' => + array( + 'woo_order_count_smaller_equal' . $conditionKeySuffix => array( + '(' . $order_count_query . ')', + '<=', + '%d', + $condition['value'], + ), + ), + ); + } elseif ( $condition['operator'] == 'intrange' ) { + return array( + 'additionalWhereArr' => + array( + 'woo_order_count_larger' . $conditionKeySuffix => array( + '(' . $order_count_query . ')', + '>=', + '%d', + $condition['value'], + ), + 'woo_order_count_smaller' . $conditionKeySuffix => array( + '(' . $order_count_query . ')', + '<=', + '%d', + $condition['value2'], + ), + ), + ); + } - return $startingArg; - } + return $startingArg; + } } diff --git a/projects/plugins/crm/modules/woo-sync/jpcrm-woo-sync-init.php b/projects/plugins/crm/modules/woo-sync/jpcrm-woo-sync-init.php index 7ac8f591042d..a35be2ab169f 100644 --- a/projects/plugins/crm/modules/woo-sync/jpcrm-woo-sync-init.php +++ b/projects/plugins/crm/modules/woo-sync/jpcrm-woo-sync-init.php @@ -1,5 +1,5 @@ - 'WooSync', - 'imgstr' => '', - 'desc' => __( 'Automatically import WooCommerce data into your CRM.', 'zero-bs-crm' ), - 'url' => $zbs->urls['woosync'], - 'colour' => 'rgb(127 85 178)', - 'helpurl' => 'https://kb.jetpackcrm.com/article-categories/woocommerce-sync/', - 'shortname' => 'WooSync', + 'fallbackname' => 'WooSync', + 'imgstr' => '', + 'desc' => __( 'Automatically import WooCommerce data into your CRM.', 'zero-bs-crm' ), + 'url' => $zbs->urls['woosync'], + 'colour' => 'rgb(127 85 178)', + 'helpurl' => 'https://kb.jetpackcrm.com/article-categories/woocommerce-sync/', + 'shortname' => 'WooSync', ); global $jpcrm_core_extension_setting_map; $jpcrm_core_extension_setting_map['woo-sync'] = 'feat_woosync'; - // registers WooSync as a core extension, and adds to $zeroBSCRM_extensionsCompleteList global function jpcrm_register_free_extension_woosync( $exts ) { - // append our module - $exts['woo-sync'] = array( - 'name' => 'WooCommerce Sync', - 'i' => 'ext/woocommerce.png', - 'short_desc' => __( 'Automatically import WooCommerce data into your CRM.', 'zero-bs-crm' ) - ); - - return $exts; + // append our module + $exts['woo-sync'] = array( + 'name' => 'WooCommerce Sync', + 'i' => 'ext/woocommerce.png', + 'short_desc' => __( 'Automatically import WooCommerce data into your CRM.', 'zero-bs-crm' ), + ); + return $exts; } add_filter( 'jpcrm_register_free_extensions', 'jpcrm_register_free_extension_woosync' ); - // load the Woo_Sync class if feature is enabled function jpcrm_load_woo_sync() { - global $zbs; - - // Check whether old WooSync is installed, if so, deactivate in favour of core module - jpcrm_intercept_old_woosync(); + global $zbs; + + // Check whether old WooSync is installed, if so, deactivate in favour of core module + jpcrm_intercept_old_woosync(); - // load - if ( zeroBSCRM_isExtensionInstalled( 'woo-sync' ) ) { - - require_once( JPCRM_MODULES_PATH . 'woo-sync/includes/class-woo-sync.php' ); - $zbs->modules->load_module( 'woosync', 'Woo_Sync' ); + // load + if ( zeroBSCRM_isExtensionInstalled( 'woo-sync' ) ) { - } + require_once JPCRM_MODULES_PATH . 'woo-sync/includes/class-woo-sync.php'; + $zbs->modules->load_module( 'woosync', 'Woo_Sync' ); + } } add_action( 'jpcrm_load_modules', 'jpcrm_load_woo_sync' ); - /** * Where WooSync is installed as an extension, deactivate it */ @@ -82,7 +76,7 @@ function jpcrm_intercept_old_woosync() { wp_clear_scheduled_hook( 'zerobscrm_woosync_hourly_sync' ); // check not fired within past day $existing_transient = get_transient( 'woosync.conflict.deactivated' ); - if ( !$existing_transient ) { + if ( ! $existing_transient ) { // add notice & transient zeroBSCRM_notifyme_insert_notification( get_current_user_id(), -999, -1, 'woosync.conflict.deactivated', '' ); @@ -139,15 +133,12 @@ function jpcrm_warning_message_woosync_ext( $actions, $plugin_file = '', $plugin return $actions; } -add_filter( 'plugin_action_links', 'jpcrm_warning_message_woosync_ext', 10, 3); - - +add_filter( 'plugin_action_links', 'jpcrm_warning_message_woosync_ext', 10, 3 ); // Install function function zeroBSCRM_extension_install_woo_sync() { - - return jpcrm_install_core_extension( 'woo-sync' ); + return jpcrm_install_core_extension( 'woo-sync' ); } // Uninstall function @@ -156,29 +147,27 @@ function zeroBSCRM_extension_uninstall_woo_sync() { // remove cron wp_clear_scheduled_hook( 'jpcrm_woosync_sync' ); return jpcrm_uninstall_core_extension( 'woo-sync' ); - } // Sniffs for WooCommerce, and puts out notification when we have woo but no woosync function jpcrm_sniff_feature_woosync() { - global $zbs; - - // where we've not got WooSync active.. - if ( !zeroBSCRM_isExtensionInstalled( 'woo-sync' ) ) { - - // check if WooCommerce _is_ active & prompt - $zbs->feature_sniffer->sniff_for_plugin( - array( - 'feature_slug' => 'woocommerce', - 'plugin_slug' => 'woocommerce/woocommerce.php', - 'more_info_link' => $zbs->urls['kb-woosync-home'], - 'is_module' => true, - ) - ); + global $zbs; - } + // where we've not got WooSync active.. + if ( ! zeroBSCRM_isExtensionInstalled( 'woo-sync' ) ) { + + // check if WooCommerce _is_ active & prompt + $zbs->feature_sniffer->sniff_for_plugin( + array( + 'feature_slug' => 'woocommerce', + 'plugin_slug' => 'woocommerce/woocommerce.php', + 'more_info_link' => $zbs->urls['kb-woosync-home'], + 'is_module' => true, + ) + ); + } } add_action( 'jpcrm_sniff_features', 'jpcrm_sniff_feature_woosync' ); @@ -218,11 +207,9 @@ function jpcrm_add_woo_jobs_to_system_assistant( $job_list ) { ); } - } return $job_list; - } add_filter( 'jpcrm_system_assistant_jobs', 'jpcrm_add_woo_jobs_to_system_assistant' ); @@ -256,7 +243,7 @@ function jpcrm_woosync_is_hpos_enabled() { // Extension legacy definitions if ( ! defined( 'JPCRM_WOO_SYNC_ROOT_FILE' ) ) { - define( 'JPCRM_WOO_SYNC_ROOT_FILE', __FILE__ ); - define( 'JPCRM_WOO_SYNC_ROOT_PATH', plugin_dir_path( __FILE__ ) ); - define( 'JPCRM_WOO_SYNC_IMAGE_URL', plugin_dir_url( JPCRM_WOO_SYNC_ROOT_FILE ) . 'i/' ); + define( 'JPCRM_WOO_SYNC_ROOT_FILE', __FILE__ ); + define( 'JPCRM_WOO_SYNC_ROOT_PATH', plugin_dir_path( __FILE__ ) ); + define( 'JPCRM_WOO_SYNC_IMAGE_URL', plugin_dir_url( JPCRM_WOO_SYNC_ROOT_FILE ) . 'i/' ); }