Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 524
0.00% covered (danger)
0.00%
0 / 14
CRAP
n/a
0 / 0
zeroBSCRM_fields_initialise
0.00% covered (danger)
0.00%
0 / 102
0.00% covered (danger)
0.00%
0 / 1
2
zeroBSCRM_internalAddressFieldMods
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
zeroBSCRM_unpackCustomFields
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
182
zeroBSCRM_customFields_applyFieldToGlobal
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
90
zeroBSCRM_unpackCustomisationsToFields
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
420
zeroBSCRM_applyFieldSorts
0.00% covered (danger)
0.00%
0 / 120
0.00% covered (danger)
0.00%
0 / 1
9312
zeroBSCRM_customerFields_select
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
110
zeroBSCRM_customerFields_getSimpleArr
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
110
zeroBSCRM_save_fields
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
90
zeroBSCRM_customFields_getSlugOrCreate
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
210
zeroBSCRM_customfields_acceptableCFTypes
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
2
zeroBSCRM_customFields_parseAutoNumberStr
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
42
zeroBSCRM_customFields_getAutoNumber
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
210
zeroBSCRM_customFields_processCustomField
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2/*
3 * Jetpack CRM
4 * https://jetpackcrm.com
5 * V1.1.19
6 *
7 * Copyright 2020 Automattic
8 *
9 * Date: 18/10/16
10 */
11
12/*
13======================================================
14    Breaking Checks ( stops direct access )
15    ====================================================== */
16if ( ! defined( 'ZEROBSCRM_PATH' ) ) {
17    exit( 0 );
18}
19/*
20======================================================
21    / Breaking Checks
22    ====================================================== */
23
24        global $zbsFieldsEnabled, $zbsFieldSorts, $zbsAddressFields;
25        $zbsFieldsEnabled = array(); // } ALSO added 'opt' field #} if this is set it'll be checked whether $zbsFieldsEnabled['optname'] global is true/false
26        $zbsFieldSorts    = array();
27        $zbsAddressFields = array();
28
29        // these are all DAL3 Object Loaded via zeroBSCRM_fields_initialise():
30        global $zbsCustomerFields, $zbsCompanyFields, $zbsCustomerQuoteFields, $zbsCustomerInvoiceFields, $zbsTransactionFields, $zbsFormFields;
31        $zbsCustomerFields        = array();
32        $zbsCompanyFields         = array();
33        $zbsCustomerQuoteFields   = array();
34        $zbsCustomerInvoiceFields = array();
35        $zbsTransactionFields     = array();
36        $zbsFormFields            = array();
37
38    // This takes all the DAL3 object models and builds out fieldGlobalArrays
39    // ... as was hard-typed in < v3.0
40    // ... Addresses still hard typed as 3.0, but rest model-generated
41    // This gets run in Core.php after initialising zbsDAL class
42function zeroBSCRM_fields_initialise() {
43
44    global $zbs, $zbsFieldsEnabled, $zbsFieldSorts, $zbsAddressFields;
45    global $zbsCustomerFields, $zbsCompanyFields, $zbsCustomerQuoteFields, $zbsCustomerInvoiceFields, $zbsTransactionFields, $zbsFormFields;
46
47    /*
48    ======================================================
49    Legacy / Unchanged
50    ======================================================
51    */
52
53    $zbsAddressFields = array(
54        'addr1'    => array(
55            'text',
56            __( 'Address Line 1', 'zero-bs-crm' ),
57            '',
58            'area' => 'Main Address',
59        ),
60        'addr2'    => array(
61            'text',
62            __( 'Address Line 2', 'zero-bs-crm' ),
63            '',
64            'area' => 'Main Address',
65        ),
66        'city'     => array(
67            'text',
68            __( 'City', 'zero-bs-crm' ),
69            'e.g. New York',
70            'area' => 'Main Address',
71        ),
72        'county'   => array(
73            'text',
74            __( 'County', 'zero-bs-crm' ),
75            'e.g. Kings County',
76            'area' => 'Main Address',
77        ),
78        'postcode' => array(
79            'text',
80            __( 'Postcode', 'zero-bs-crm' ),
81            'e.g. 10019',
82            'area' => 'Main Address',
83        ),
84        'country'  => array(
85            'text',
86            __( 'Country', 'zero-bs-crm' ),
87            'e.g. UK',
88            'area' => 'Main Address',
89        ),
90
91    );
92
93    // } Global Default sort for all "addresses" (to be used for all address outputs)
94    $zbsFieldSorts['address'] = array(
95
96        // } Default order
97        'default' => array(
98            'addr1',
99            'addr2',
100            'city',
101            'county',
102            'postcode',
103            'country',
104        ),
105
106    );
107
108    /*
109    ======================================================
110    / Legacy / Unchanged
111    ======================================================
112    */
113
114    /*
115    ======================================================
116    Contacts
117    ======================================================
118    */
119
120    // Load from  object model :)
121    $zbsCustomerFields = $zbs->DAL->contacts->generateFieldsGlobalArr();
122
123    // } Default sort (still hard-typed for now)
124    $zbsFieldSorts['customer'] = array(
125
126        // } Default order
127            'default' => array(
128
129                'status',
130                'prefix',
131                'fname',
132                'lname',
133                /*
134                        addresses subordinated to global "address" field sort
135                        'addr1',
136                        'addr2',
137                        'city',
138                        'county',
139                        'postcode',
140                     */
141                    'addresses',  // } This indicates addresses
142                'hometel',
143                'worktel',
144                'mobtel',
145                'email',
146                'notes',
147            ),
148
149    );
150
151    /*
152    ======================================================
153    / Contacts
154    ======================================================
155    */
156
157    /*
158    ======================================================
159    Companies
160    ======================================================
161    */
162
163    // Load from  object model :)
164    $zbsCompanyFields = $zbs->DAL->companies->generateFieldsGlobalArr();
165
166    // } Default sort (still hard-typed for now)
167    $zbsFieldSorts['company'] = array(
168
169        // } Default order
170            'default' => array(
171
172                'status',
173                'name', // coname
174                    /*
175                        addresses subordinated to global "address" field sort
176                        'addr1',
177                        'addr2',
178                        'city',
179                        'county',
180                        'postcode',
181                     */
182                'addresses', // } This indicates addresses
183                'maintel',
184                'sectel',
185                'mobtel',
186                'email',
187                'notes',
188            ),
189
190    );
191
192    /*
193    ======================================================
194    / Companies
195    ======================================================
196    */
197
198    /*
199    ======================================================
200    Quotes
201    ======================================================
202    */
203
204    // Load from  object model :)
205    $zbsCustomerQuoteFields = $zbs->DAL->quotes->generateFieldsGlobalArr();
206
207    // } Default sort (still hard-typed for now)
208    $zbsFieldSorts['quote'] = array(
209
210        // } Default order
211        'default' => array(
212
213            'title', // name
214            'value', // val
215            'date',
216            'notes',
217        ),
218
219    );
220
221    /*
222    ======================================================
223    / Quotes
224    ======================================================
225    */
226
227    /*
228    ======================================================
229    Invoices
230    ======================================================
231    */
232
233    /*
234    NOTE:
235
236    $zbsCustomerInvoiceFields Removed as of v3.0, invoice builder is very custom, UI wise,
237    .. and as the model can deal with saving + custom fields WITHOUT the global, there's no need
238    (whereas other objects input views are directed by these globals, Invs is separate, way MS made it)
239
240
241
242    // Load from  object model :)
243    $zbsCustomerInvoiceFields = $zbs->DAL->invoices->generateFieldsGlobalArr();
244
245    #} Default sort (still hard-typed for now)
246    $zbsFieldSorts['invoice'] = array(
247
248            #} Default order
249            'default' => array(
250
251                    'status',
252                    'no',
253                    'date',
254                    'notes',
255                    'ref',
256                    'due',
257                    'logo',
258                    'bill',
259                    'ccbill'
260                )
261
262        );
263
264     */
265
266    /*
267    ======================================================
268    / Invoices
269    ======================================================
270    */
271
272    /*
273    ======================================================
274    Transactions
275    ======================================================
276    */
277
278    // Load from  object model :)
279    $zbsTransactionFields = $zbs->DAL->transactions->generateFieldsGlobalArr();
280
281    // } Default sort (still hard-typed for now)
282    /*
283        not used, yet?
284    $zbsFieldSorts['transactions'] = array(
285
286            #} Default order
287            'default' => array(
288
289                )
290
291        );
292     */
293
294    /*
295    ======================================================
296    / Transactions
297    ======================================================
298    */
299
300    /*
301    ======================================================
302    Forms
303    ======================================================
304    */
305
306    // Load from  object model :)
307    $zbsFormFields = $zbs->DAL->forms->generateFieldsGlobalArr();
308
309    // } Default sort (still hard-typed for now)
310    $zbsFieldSorts['form'] = array(
311
312        // } Default order
313        'default' => array(
314
315            'header',
316            'subheader',
317            'fname',
318            'lname',
319            'email',
320            'notes',
321            'submit',
322            'spam',
323            'success',
324        ),
325
326    );
327
328    /*
329    ======================================================
330    / Forms
331    ======================================================
332    */
333}
334
335/*
336======================================================
337    Hard Coded Fields + Sorts
338    (Defaults which can be overriden by custom fields + field sorts)
339    ====================================================== */
340
341    // } Below are HARD CODED fields :)
342
343    // } NOTE:
344    // } Added an additional field to each field 'area'
345    // } adding this (any text) will group these into a "subset" with title of 'area'
346    // } they MUST (currently) be in sequential order!!!
347
348    /*
349    DAL3 Notes:
350
351        #globalfieldobjsdal3
352
353        This ultimately becomes #legacy. This global $fields var collection was
354        written way back at the beginning when we were doing all kinds of rough dev.
355        Now, these are kind of derelict technical debt, really replaced by DAL obj models.
356        To defer the work in this cycle, I've left these here (as doing DAL3 translation)
357        because to remove them at this point is like peeling off a symbiote.
358        ... so, for near future, let's see how they play out.
359
360        DAL3 Obj models + legacy $fields globals. I suppose the field globals are kind of
361        "UI visible" variants of obj models... that's how they operate, for now, at least.
362
363        // interesting use: DAL2 core, func: ->objModel($type=1)
364
365        WH 12/2/19
366
367
368        TBC ... yeah this was legacy. I split this from ZeroBSCRM.Fields.php into it's own DAL3 drop-in replacement
369        because the old way was far too clunky when we have proper models now. But rather than being model-based here
370        ... I've opted for a second layer (maintain existing, just tweak the names where they've changed)
371        ... e.g. Quote "name" => "title"
372
373
374        WH 22/3/19
375
376    */
377
378/*
379======================================================
380    Field & Sort Functions
381    (These build out custom field arrs by working on defaults from above)
382    ====================================================== */
383
384    // } Currently this is just "add countries" or dont
385function zeroBSCRM_internalAddressFieldMods() {
386
387    global $zbs;
388
389    $addCountries = $zbs->settings->get( 'countries' );
390    if ( isset( $addCountries ) && $addCountries ) {
391
392        // } add it
393        global $zbsAddressFields, $zbsFieldSorts;
394        $zbsAddressFields['country'] = array(
395            'selectcountry',
396            __( 'Country', 'zero-bs-crm' ),
397            'e.g. United Kingdom',
398            'area' => 'Main Address',
399        );
400
401        // } add to sort
402        $zbsFieldSorts['address']['default'][] = 'country';
403
404    }
405}
406
407    // } Unpack any custom fields + add
408function zeroBSCRM_unpackCustomFields() {
409
410    // } Jammed for now, adds country if set!
411    zeroBSCRM_internalAddressFieldMods();
412
413    global $zbs, $zbsAddressFields, $zbsFieldSorts;
414
415    $customfields = $zbs->settings->get( 'customfields' );
416
417    $key_driven_custom_fields = array(
418        // these get DAL3 Custom fields
419        'customers'    => ZBS_TYPE_CONTACT,
420        'companies'    => ZBS_TYPE_COMPANY,
421        'quotes'       => ZBS_TYPE_QUOTE,
422        'transactions' => ZBS_TYPE_TRANSACTION,
423        'invoices'     => ZBS_TYPE_INVOICE,
424        'addresses'    => ZBS_TYPE_ADDRESS,
425    );
426
427    // Following overloading code is also replicated in AdminPages.php (settings page), search #FIELDOVERLOADINGDAL2+
428
429    foreach ( $key_driven_custom_fields as $key => $obj_type_id ) {
430
431        if ( isset( $customfields ) && isset( $customfields[ $key ] ) ) {
432
433                // turn ZBS_TYPE_CONTACT (1) into "contact"
434                $obj_type_str = $zbs->DAL->objTypeKey( $obj_type_id ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
435            if ( ! empty( $obj_type_str ) ) {
436                $customfields[ $key ] = $zbs->DAL->setting( 'customfields_' . $obj_type_str, array() ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
437            }
438        }
439    }
440
441        // / field overloading
442
443    if ( isset( $customfields ) && is_array( $customfields ) ) {
444
445            // v3rc2, this doesn't appear to be needed, already loaded above?
446            // left in as fallback
447        if ( isset( $customfields['addresses'] ) && is_array( $customfields['addresses'] ) && count( $customfields['addresses'] ) > 0 ) {
448            $addrCustomFields = $customfields['addresses'];
449        } else {
450            $addrCustomFields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => ZBS_TYPE_ADDRESS ) );
451        }
452
453            // } Addresses
454        if ( is_array( $addrCustomFields ) && count( $addrCustomFields ) > 0 ) {
455
456            $cfIndx = 1;
457            foreach ( $addrCustomFields as $fieldKey => $field ) {
458
459                // unpacks csv options and sets 'custom-field' attr
460                $fieldO = zeroBSCRM_customFields_processCustomField( $field );
461
462                // } Add it to arr
463                // v2 method $zbsAddressFields['cf'.$cfIndx] = $fieldO;
464                // v3:
465                $zbsAddressFields[ 'addr_' . $fieldKey ] = $fieldO;
466
467                // } increment
468                ++$cfIndx;
469
470                // } Also add it to the list of "default sort" at end
471                $zbsFieldSorts['address']['default'][] = 'addr_' . $fieldKey;
472
473            }
474        }
475
476            // } Customers
477            $customfields = zeroBSCRM_customFields_applyFieldToGlobal( $customfields, 'customers', 'customer', 'zbsCustomerFields' );
478
479            // } Companies
480            $customfields = zeroBSCRM_customFields_applyFieldToGlobal( $customfields, 'companies', 'company', 'zbsCompanyFields' );
481
482            // } Quotes
483            $customfields = zeroBSCRM_customFields_applyFieldToGlobal( $customfields, 'quotes', 'quote', 'zbsCustomerQuoteFields' );
484
485            // } Invoices
486            $customfields = zeroBSCRM_customFields_applyFieldToGlobal( $customfields, 'invoices', 'invoice', 'zbsCustomerInvoiceFields' );
487
488            // } Transactions
489            $customfields = zeroBSCRM_customFields_applyFieldToGlobal( $customfields, 'transactions', 'transaction', 'zbsTransactionFields' );
490
491    } // if isset + is array
492}
493
494    // this takes the custom fields from DB storage (passed) and translate them into the globals (e.g. $zbsCompanyFields)
495    // ... a lot of the linkages here are DAL1 legacy stuff, probably need rethinking v3+
496    // $customFields = settings['customfields']
497    // $key = 'companies' (< DAL2 customFields key)
498    // $keyFieldSorts = 'company' (proper DAL2 key used for field sorts)
499    // $globalVarName = 'zbsCompanyFields' (the global storing the field obj)
500function zeroBSCRM_customFields_applyFieldToGlobal( $customFields, $key, $keyFieldSorts, $globalVarName ) {
501
502    if ( ! empty( $globalVarName ) && is_array( $customFields ) && ! empty( $key ) && isset( $customFields[ $key ] ) && is_array( $customFields[ $key ] ) && count( $customFields[ $key ] ) > 0 ) {
503
504        // globalise, e.g. global $zbsCompanyFields;
505        global $zbs, $zbsFieldSorts;
506
507        $cfIndx = 1;
508        if ( is_array( $customFields[ $key ] ) ) {
509
510            foreach ( $customFields[ $key ] as $fieldKey => $field ) {
511
512                // unpacks csv options and sets 'custom-field' attr
513                $fieldO = zeroBSCRM_customFields_processCustomField( $field );
514
515                // } Add it to arr
516                $GLOBALS[ $globalVarName ][ $fieldKey ] = $fieldO;
517
518                // } increment
519                ++$cfIndx;
520
521                // } Also add it to the list of "default sort" at end
522                $zbsFieldSorts[ $keyFieldSorts ]['default'][] = $fieldKey;
523
524                unset( $fieldKey );
525
526            } // foreach field
527
528        } // if custom fields is array
529
530    } // if issets
531
532    return $customFields;
533}
534
535    // } Retrieves any potential tweaks from options obj
536function zeroBSCRM_unpackCustomisationsToFields() {
537
538    global $zbs;
539
540    $customisedfields = $zbs->settings->get( 'customisedfields' );
541
542    $allowedCustomisation = array(
543
544        'customers'    => array(
545            'status',
546            'prefix',
547        ),
548        'companies'    => array(
549            'status',
550        ),
551        'quotes'       => array(),
552        'invoices'     => array(),
553        'transactions' => array(),
554        'addresses'    => array(),
555
556    );
557
558    if ( isset( $customisedfields ) && is_array( $customisedfields ) ) {
559
560        foreach ( $allowedCustomisation as $allowKey => $allowFields ) {
561
562            if ( is_array( $allowFields ) && count( $allowFields ) ) {
563                foreach ( $allowFields as $field ) {
564
565                    // } Corresponding option?
566                    if ( isset( $customisedfields ) && isset( $customisedfields[ $allowKey ] ) && isset( $customisedfields[ $allowKey ][ $field ] ) ) {
567
568                        // } $customisedfields[$allowKey][$field][0] will be (as of yet unused) show/hide flag
569                        // } $customisedfields[$allowKey][$field][1] will be new optionval
570
571                        // } option override present :)
572                        // } Brutal, needs reworking
573                        switch ( $allowKey ) {
574
575                            case 'customers':
576                                global $zbsCustomerFields;
577
578                                if ( $field == 'status' && isset( $zbsCustomerFields['status'] ) ) {
579
580                                    // } Rebuild options ($arr[3])
581                                    $opts                           = explode( ',', $customisedfields[ $allowKey ][ $field ][1] );
582                                    $zbsCustomerFields['status'][3] = $opts;
583
584                                }
585
586                                if ( $field == 'prefix' && isset( $zbsCustomerFields['prefix'] ) ) {
587
588                                    // } Rebuild options ($arr[3])
589                                    $opts                           = explode( ',', $customisedfields[ $allowKey ][ $field ][1] );
590                                    $zbsCustomerFields['prefix'][3] = $opts;
591
592                                }
593
594                                break;
595
596                            case 'companies':
597                                global $zbsCompanyFields;
598
599                                if ( $field == 'status' && isset( $zbsCompanyFields['status'] ) ) {
600
601                                    // } Rebuild options ($arr[3])
602                                    $opts                          = explode( ',', $customisedfields[ $allowKey ][ $field ][1] );
603                                    $zbsCompanyFields['status'][3] = $opts;
604
605                                }
606
607                                break;
608                            case 'quotes':
609                                // Nothing yet
610                                break;
611                            case 'invoices':
612                                // Nothing yet
613                                break;
614
615                        }
616                    }
617                }
618            }
619        } // / foreach
620
621    } // / isset
622}
623
624    // } field sorts
625function zeroBSCRM_applyFieldSorts() {
626
627    // } localise
628    global $zbs, $zbsFieldSorts, $zbsCustomerFields, $zbsFieldsEnabled, $zbsCompanyFields, $zbsCustomerQuoteFields, $zbsCustomerInvoiceFields, $zbsFormFields, $zbsAddressFields;
629
630    // } Work through diff zones + rearrange field arrays
631    // } Does so by: 1) using any overrides stored in "fieldsorts" in settings, then 2) defaults where no overrides
632    $fieldSortOverrides = $zbs->settings->get( 'fieldsorts' );
633
634    // quick add: Field hides
635    // no actually, don't do hide at this level... $fieldHideOverrides = $zbs->settings->get('fieldhides');
636
637    // } Exclusions
638    $exclusions = array( 'addresses' );
639
640        // } =================================================================================
641        // } Addresses (global)
642        // } =================================================================================
643        $addressDefaultsPresent = false;
644    if ( isset( $zbsFieldSorts['address'] ) && isset( $zbsFieldSorts['address']['default'] ) && is_array( $zbsFieldSorts['address']['default'] ) && count( $zbsFieldSorts['address']['default'] ) > 0 ) {
645
646        // } Use defaults or overrides?
647        $addressFieldSortSource = $zbsFieldSorts['address']['default']; // NOTE IN THIS INSTANCE THIS IS USED A LOT BELOW!
648        if ( isset( $fieldSortOverrides['address'] ) && is_array( $fieldSortOverrides['address'] ) && count( $fieldSortOverrides['address'] ) > 0 ) {
649            $addressFieldSortSource = $fieldSortOverrides['address'];
650        }
651
652        // } new arr
653        $newAddressFieldsArr = array();
654
655        // } Cycle through defaults/overrides first... and pull through in correct order
656        foreach ( $addressFieldSortSource as $key ) {
657
658            // } if exists, add to newcustomerfieldsarr
659            if ( ! in_array( $key, $exclusions ) && isset( $zbsAddressFields[ $key ] ) ) {
660
661                // } just copy it through
662                $newAddressFieldsArr[ $key ] = $zbsAddressFields[ $key ];
663
664            } else {
665
666                // if doesn't exist, that's weird, or it's an exclusion (address fields are clumped together)
667
668                // nothing here as in addresses (global)
669
670            }
671        }
672
673        // } Then cycle through original obj and add any that got missed by defaults list...
674        foreach ( $zbsAddressFields as $key => $field ) {
675
676            if ( ! array_key_exists( $key, $newAddressFieldsArr ) ) {
677
678                // } Add it to the end
679                $newAddressFieldsArr[ $key ] = $field;
680
681            }
682        }
683
684        // } Copy over arr :)
685        $zbsAddressFields = $newAddressFieldsArr;
686
687        $addressDefaultsPresent = true;
688
689    }
690
691        // } NOTES ON ADDRESSES: #NOTESONADDRESS
692        /*
693            at this point the addressfields obj is a global "template" for how users want addresses to show up.
694            ... for now we'll just add the fields from here (x2 with second having prefix secaddr_) in place of "addresses"
695            but needs adjustment/refactoring
696
697        */
698
699        // } =================================================================================
700        // } Customers
701        // } =================================================================================
702    if ( isset( $zbsFieldSorts['customer'] ) && isset( $zbsFieldSorts['customer']['default'] ) && is_array( $zbsFieldSorts['customer']['default'] ) && count( $zbsFieldSorts['customer']['default'] ) > 0 ) {
703
704        // } Use defaults or overrides?
705        $customerFieldSortSource = $zbsFieldSorts['customer']['default'];
706        if ( isset( $fieldSortOverrides['customer'] ) && is_array( $fieldSortOverrides['customer'] ) && count( $fieldSortOverrides['customer'] ) > 0 ) {
707            $customerFieldSortSource = $fieldSortOverrides['customer'];
708        }
709
710        // } new arr
711        $newCustomerFieldsArr = array();
712
713        // } Cycle through defaults first... and pull through in correct order
714        foreach ( $customerFieldSortSource as $key ) {
715
716            // } if exists, add to newcustomerfieldsarr
717            if ( ! in_array( $key, $exclusions ) && isset( $zbsCustomerFields[ $key ] ) ) {
718
719                // } just copy it through
720                // unless it's a hide!
721                $newCustomerFieldsArr[ $key ] = $zbsCustomerFields[ $key ];
722                /*
723                    no actually, don't do hide at this level...
724
725                if (isset($fieldHideOverrides['customer']) && is_array($fieldHideOverrides['customer'])){
726                    if (in_array($key, $fieldHideOverrides['customer'])){
727
728                        // hide
729
730                    } else {
731
732                        // show
733                        $newCustomerFieldsArr[$key] = $zbsCustomerFields[$key];
734
735                    }
736
737                }
738
739                */
740
741            } else {
742
743                // if doesn't exist, that's weird, or it's an exclusion (address fields are clumped together)
744
745                if ( $key == 'addresses' ) {
746
747                    // } Add all fields here for now... not ideal, but okay.
748                    // } Uses Address field sort tho :)
749
750                    // } Customers have 2 addresses:
751                    if ( $addressDefaultsPresent ) {
752
753                        // } Quick design to use address as template, see #NOTESONADDRESS
754
755                        // } Add addr 1 fields
756                        foreach ( $addressFieldSortSource as $addrFieldKey ) {
757
758                            // } If we've left attr on obj (legacy), use that field, otherwise copy a new field in from $zbsAddressFields obj
759                            // } e.g. addr1 etc. but if user added cf1 to addresses...
760
761                            // } adadpt key :/ (to stop conflicts from cf1 - this makes this addr_cf1)
762                            $adaptedFieldKey = $addrFieldKey;
763                            if ( str_starts_with( $addrFieldKey, 'cf' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
764                                $adaptedFieldKey = 'addr_' . $addrFieldKey;
765                            }
766
767                            if ( isset( $zbsCustomerFields[ $adaptedFieldKey ] ) ) {
768
769                                // } copy it through as next in line
770                                $newCustomerFieldsArr[ $adaptedFieldKey ] = $zbsCustomerFields[ $adaptedFieldKey ];
771
772                            } else {
773
774                                // } copy field inc features, from address fields (as template)
775                                // } added 1.1.19: don't copy if not set in zbsaddressfields (modified custom fields)
776                                if ( isset( $zbsAddressFields[ $addrFieldKey ] ) ) {
777                                    $newCustomerFieldsArr[ $adaptedFieldKey ] = $zbsAddressFields[ $addrFieldKey ];
778                                }
779                            }
780
781                            // }... and hacky... but ....
782                            // } main address objs also need these:,'area'=>'Main Address'
783                            if ( ! isset( $newCustomerFieldsArr[ $adaptedFieldKey ]['area'] ) ) {
784                                $newCustomerFieldsArr[ $adaptedFieldKey ]['area'] = 'Main Address';
785                            }
786                        }
787
788                        $secAddrPrefix = 'sec'; // <DAL3 $secAddrPrefix = 'secaddr_';
789
790                        // } Add addr 2 fields
791                        foreach ( $addressFieldSortSource as $addrFieldKey ) {
792
793                            // } If we've left attr on obj (legacy), use that field, otherwise copy a new field in from $zbsAddressFields obj
794                            // } e.g. addr1 etc. but if user added cf1 to addresses...
795
796                            if ( isset( $zbsCustomerFields[ $secAddrPrefix . $addrFieldKey ] ) ) {
797
798                                // } copy it through as next in line
799                                $newCustomerFieldsArr[ $secAddrPrefix . $addrFieldKey ] = $zbsCustomerFields[ $secAddrPrefix . $addrFieldKey ];
800
801                            } else {
802
803                                // } added 1.1.19: don't copy if not set in zbsaddressfields (modified custom fields)
804                                if ( isset( $zbsAddressFields[ $addrFieldKey ] ) ) {
805
806                                    // } copy field inc features, from address fields (as template)
807                                    $newCustomerFieldsArr[ $secAddrPrefix . $addrFieldKey ] = $zbsAddressFields[ $addrFieldKey ];
808
809                                    // }... and hacky... but ....
810                                    // } second address objs also need these:,'area'=>'Second Address','opt'=>'secondaddress'
811                                    $newCustomerFieldsArr[ $secAddrPrefix . $addrFieldKey ]['area'] = 'Second Address';
812                                    $newCustomerFieldsArr[ $secAddrPrefix . $addrFieldKey ]['opt']  = 'secondaddress';
813
814                                }
815                            }
816                        }
817                    }
818                }
819            }
820        }
821
822        // } Then cycle through original obj and add any that got missed by defaults list...
823        foreach ( $zbsCustomerFields as $key => $field ) {
824
825            if ( ! array_key_exists( $key, $newCustomerFieldsArr ) ) {
826
827                // } Add it to the end
828                $newCustomerFieldsArr[ $key ] = $field;
829
830            }
831        }
832
833        // } Copy over arr :)
834        $zbsCustomerFields = $newCustomerFieldsArr;
835
836    }
837
838        // } =================================================================================
839        // } Company
840        // } =================================================================================
841    if ( isset( $zbsFieldSorts['company'] ) && isset( $zbsFieldSorts['company']['default'] ) && is_array( $zbsFieldSorts['company']['default'] ) && count( $zbsFieldSorts['company']['default'] ) > 0 ) {
842
843        // } Use defaults or overrides?
844        $companyFieldSortSource = $zbsFieldSorts['company']['default'];
845        if ( isset( $fieldSortOverrides['company'] ) && is_array( $fieldSortOverrides['company'] ) && count( $fieldSortOverrides['company'] ) > 0 ) {
846            $companyFieldSortSource = $fieldSortOverrides['company'];
847        }
848
849        // } new arr
850        $newCompanyFieldsArr = array();
851
852        // } Cycle through defaults first... and pull through in correct order
853        foreach ( $companyFieldSortSource as $key ) {
854
855            // } if exists, add to newCompanyFieldsArr
856            if ( ! in_array( $key, $exclusions ) && isset( $zbsCompanyFields[ $key ] ) ) {
857
858                // } just copy it through
859                $newCompanyFieldsArr[ $key ] = $zbsCompanyFields[ $key ];
860
861            } else {
862
863                // if doesn't exist, that's weird, or it's an exclusion (address fields are clumped together)
864
865                if ( $key == 'addresses' ) {
866
867                    // } Add all fields here for now... not ideal, but okay.
868                    // } Uses Address field sort tho :)
869
870                    // } Companies have 2 addresses:
871                    if ( $addressDefaultsPresent ) {
872
873                        // } Quick design to use address as template, see #NOTESONADDRESS
874
875                        // } Add addr 1 fields
876                        foreach ( $addressFieldSortSource as $addrFieldKey ) {
877
878                            // } If we've left attr on obj (legacy), use that field, otherwise copy a new field in from $zbsAddressFields obj
879                            // } e.g. addr1 etc. but if user added cf1 to addresses...
880
881                            // } adadpt key :/ (to stop conflicts from cf1 - this makes this addr_cf1)
882                            $adaptedFieldKey = $addrFieldKey;
883                            if ( str_starts_with( $addrFieldKey, 'cf' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
884                                $adaptedFieldKey = 'addr_' . $addrFieldKey;
885                            }
886
887                            if ( isset( $zbsCompanyFields[ $adaptedFieldKey ] ) ) {
888
889                                // } copy it through as next in line
890                                $newCompanyFieldsArr[ $adaptedFieldKey ] = $zbsCompanyFields[ $adaptedFieldKey ];
891
892                            } else {
893
894                                // } copy field inc features, from address fields (as template)
895                                // } added 1.1.19: don't copy if not set in zbsaddressfields (modified custom fields)
896                                if ( isset( $zbsAddressFields[ $addrFieldKey ] ) ) {
897                                    $newCompanyFieldsArr[ $adaptedFieldKey ] = $zbsAddressFields[ $addrFieldKey ];
898                                }
899                            }
900
901                            // }... and hacky... but ....
902                            // } main address objs also need these:,'area'=>'Main Address'
903                            if ( ! isset( $newCompanyFieldsArr[ $adaptedFieldKey ]['area'] ) ) {
904                                $newCompanyFieldsArr[ $adaptedFieldKey ]['area'] = 'Main Address';
905                            }
906                        }
907
908                        $secAddrPrefix = 'sec'; // <DAL3 $secAddrPrefix = 'secaddr_';
909
910                        // } Add addr 2 fields
911                        foreach ( $addressFieldSortSource as $addrFieldKey ) {
912
913                            // } If we've left attr on obj (legacy), use that field, otherwise copy a new field in from $zbsAddressFields obj
914                            // } e.g. addr1 etc. but if user added cf1 to addresses...
915
916                            if ( isset( $zbsCompanyFields[ $secAddrPrefix . $addrFieldKey ] ) ) {
917
918                                // } copy it through as next in line
919                                $newCompanyFieldsArr[ $secAddrPrefix . $addrFieldKey ] = $zbsCompanyFields[ $secAddrPrefix . $addrFieldKey ];
920
921                            } else {
922
923                                // } added 1.1.19: don't copy if not set in zbsaddressfields (modified custom fields)
924                                if ( isset( $zbsAddressFields[ $addrFieldKey ] ) ) {
925
926                                    // } copy field inc features, from address fields (as template)
927                                    $newCompanyFieldsArr[ $secAddrPrefix . $addrFieldKey ] = $zbsAddressFields[ $addrFieldKey ];
928
929                                    // }... and hacky... but ....
930                                    // } second address objs also need these:,'area'=>'Second Address','opt'=>'secondaddress'
931                                    $newCompanyFieldsArr[ $secAddrPrefix . $addrFieldKey ]['area'] = 'Second Address';
932                                    $newCompanyFieldsArr[ $secAddrPrefix . $addrFieldKey ]['opt']  = 'secondaddress';
933
934                                }
935                            }
936                        }
937                    }
938                }
939            }
940        }
941
942        // } Then cycle through original obj and add any that got missed by defaults list...
943        foreach ( $zbsCompanyFields as $key => $field ) {
944
945            if ( ! array_key_exists( $key, $newCompanyFieldsArr ) ) {
946
947                // } Add it to the end
948                $newCompanyFieldsArr[ $key ] = $field;
949
950            }
951        }
952
953        // } Copy over arr :)
954        $zbsCompanyFields = $newCompanyFieldsArr;
955
956    }
957
958        // } =================================================================================
959        // } Quote
960        // } =================================================================================
961    if ( isset( $zbsFieldSorts['quote'] ) && isset( $zbsFieldSorts['quote']['default'] ) && is_array( $zbsFieldSorts['quote']['default'] ) && count( $zbsFieldSorts['quote']['default'] ) > 0 ) {
962
963        // } Use defaults or overrides?
964        $quoteFieldSortSource = $zbsFieldSorts['quote']['default'];
965        if ( isset( $fieldSortOverrides['quote'] ) && is_array( $fieldSortOverrides['quote'] ) && count( $fieldSortOverrides['quote'] ) > 0 ) {
966            $quoteFieldSortSource = $fieldSortOverrides['quote'];
967        }
968
969        // } new arr
970        $newQuoteFieldsArr = array();
971
972        // } Cycle through defaults first... and pull through in correct order
973        foreach ( $quoteFieldSortSource as $key ) {
974
975            // } if exists, add to newQuoteFieldsArr
976            if ( ! in_array( $key, $exclusions ) && isset( $zbsCustomerQuoteFields[ $key ] ) ) {
977
978                // } just copy it through
979                $newQuoteFieldsArr[ $key ] = $zbsCustomerQuoteFields[ $key ];
980
981            } else {
982
983                // if doesn't exist, that's weird, or it's an exclusion (address fields are clumped together)
984
985                if ( $key == 'addresses' ) {
986
987                    // } Quotes have none.
988
989                }
990            }
991        }
992
993        // } Then cycle through original obj and add any that got missed by defaults list...
994        foreach ( $zbsCustomerQuoteFields as $key => $field ) {
995
996            if ( ! array_key_exists( $key, $newQuoteFieldsArr ) ) {
997
998                // } Add it to the end
999                $newQuoteFieldsArr[ $key ] = $field;
1000
1001            }
1002        }
1003
1004        // } Copy over arr :)
1005        $zbsCustomerQuoteFields = $newQuoteFieldsArr;
1006
1007    }
1008
1009        // } =================================================================================
1010        // } Invoice
1011        // } =================================================================================
1012    if ( isset( $zbsFieldSorts['invoice'] ) && isset( $zbsFieldSorts['invoice']['default'] ) && is_array( $zbsFieldSorts['invoice']['default'] ) && count( $zbsFieldSorts['invoice']['default'] ) > 0 ) {
1013
1014        // } Use defaults or overrides?
1015        $invoiceFieldSortSource = $zbsFieldSorts['invoice']['default'];
1016        if ( isset( $fieldSortOverrides['invoice'] ) && is_array( $fieldSortOverrides['invoice'] ) && count( $fieldSortOverrides['invoice'] ) > 0 ) {
1017            $invoiceFieldSortSource = $fieldSortOverrides['invoice'];
1018        }
1019
1020        // } new arr
1021        $newInvoiceFieldsArr = array();
1022
1023        // } Cycle through defaults first... and pull through in correct order
1024        foreach ( $invoiceFieldSortSource as $key ) {
1025
1026            // } if exists, add to newInvoiceFieldsArr
1027            if ( ! in_array( $key, $exclusions ) && isset( $zbsCustomerInvoiceFields[ $key ] ) ) {
1028
1029                // } just copy it through
1030                $newInvoiceFieldsArr[ $key ] = $zbsCustomerInvoiceFields[ $key ];
1031
1032            } else {
1033
1034                // if doesn't exist, that's weird, or it's an exclusion (address fields are clumped together)
1035
1036                if ( $key == 'addresses' ) {
1037
1038                    // } Invs have none.
1039
1040                }
1041            }
1042        }
1043
1044        // } Then cycle through original obj and add any that got missed by defaults list...
1045        foreach ( $zbsCustomerInvoiceFields as $key => $field ) {
1046
1047            if ( ! array_key_exists( $key, $newInvoiceFieldsArr ) ) {
1048
1049                // } Add it to the end
1050                $newInvoiceFieldsArr[ $key ] = $field;
1051
1052            }
1053        }
1054
1055        // } Copy over arr :)
1056        $zbsCustomerInvoiceFields = $newInvoiceFieldsArr;
1057
1058    }
1059
1060        // } =================================================================================
1061        // } Forms
1062        // } =================================================================================
1063    if ( isset( $zbsFieldSorts['form'] ) && isset( $zbsFieldSorts['form']['default'] ) && is_array( $zbsFieldSorts['form']['default'] ) && count( $zbsFieldSorts['form']['default'] ) > 0 ) {
1064
1065        // } Use defaults or overrides?
1066        $formFieldSortSource = $zbsFieldSorts['form']['default'];
1067        if ( isset( $fieldSortOverrides['form'] ) && is_array( $fieldSortOverrides['form'] ) && count( $fieldSortOverrides['form'] ) > 0 ) {
1068            $formFieldSortSource = $fieldSortOverrides['form'];
1069        }
1070
1071        // } new arr
1072        $newFormFieldsArr = array();
1073
1074        // } Cycle through defaults first... and pull through in correct order
1075        foreach ( $formFieldSortSource as $key ) {
1076
1077            // } if exists, add to newFormFieldsArr
1078            if ( ! in_array( $key, $exclusions ) && isset( $zbsFormFields[ $key ] ) ) {
1079
1080                // } just copy it through
1081                $newFormFieldsArr[ $key ] = $zbsFormFields[ $key ];
1082
1083            } else {
1084
1085                // if doesn't exist, that's weird, or it's an exclusion (address fields are clumped together)
1086
1087                if ( $key == 'addresses' ) {
1088
1089                    // } Invs have none.
1090
1091                }
1092            }
1093        }
1094
1095        // } Then cycle through original obj and add any that got missed by defaults list...
1096        foreach ( $zbsFormFields as $key => $field ) {
1097
1098            if ( ! array_key_exists( $key, $newFormFieldsArr ) ) {
1099
1100                // } Add it to the end
1101                $newFormFieldsArr[ $key ] = $field;
1102
1103            }
1104        }
1105
1106        // } Copy over arr :)
1107        $zbsFormFields = $newFormFieldsArr;
1108
1109    }
1110}
1111/*
1112======================================================
1113    / Field & Sort Functions
1114    ====================================================== */
1115
1116/*
1117======================================================
1118    Field Helper funcs
1119    ====================================================== */
1120
1121    // mikes, WH took from automations v0.1
1122
1123        // from Export file and customer meta ..  functionised..
1124function zeroBSCRM_customerFields_select( $form_id, $form_name ) {
1125    global $zbsCustomerFields;
1126    $fields        = $zbsCustomerFields;
1127    $useSecondAddr = zeroBSCRM_getSetting( 'secondaddress' );
1128    global $zbsFieldsEnabled;
1129    if ( $useSecondAddr == '1' ) {
1130        $zbsFieldsEnabled['secondaddress'] = true;
1131    }
1132
1133    $output = "<select id='" . $form_id . "' name='" . $form_name . "'>";
1134    foreach ( $fields as $fieldK => $fieldV ) {
1135
1136        $showField = true;
1137
1138        // } Check if not hard-hidden by opt override (on off for second address, mostly)
1139        if ( isset( $fieldV['opt'] ) && ( ! isset( $zbsFieldsEnabled[ $fieldV['opt'] ] ) || ! $zbsFieldsEnabled[ $fieldV['opt'] ] ) ) {
1140            $showField = false;
1141        }
1142
1143        // or is hidden by checkbox?
1144        if ( isset( $fieldHideOverrides['company'] ) && is_array( $fieldHideOverrides['company'] ) ) {
1145            if ( in_array( $fieldK, $fieldHideOverrides['company'] ) ) {
1146                $showField = false;
1147            }
1148        }
1149
1150                // } If show...
1151        if ( $showField ) {
1152            $output .= '<option value="' . $fieldK . '" /> ' . $fieldV[1] . '<br />';
1153        } // } / if show
1154    }
1155    $output .= '</select>';
1156    return $output;
1157}
1158
1159    // WH: Made simple "get customer fields array simple" for mc2
1160function zeroBSCRM_customerFields_getSimpleArr() {
1161
1162    // taken mostly from the customer metabox
1163
1164        global $zeroBSCRM_Settings;
1165
1166        // Get field Hides...
1167        $fieldHideOverrides = $zeroBSCRM_Settings->get( 'fieldhides' );
1168
1169        global $zbsCustomerFields;
1170        $fields = $zbsCustomerFields;
1171
1172        // } Using second address?
1173        $useSecondAddr = zeroBSCRM_getSetting( 'secondaddress' );
1174        $showCountries = zeroBSCRM_getSetting( 'countries' );
1175
1176        // } Hiding address inputs?
1177        $showAddr = zeroBSCRM_getSetting( 'showaddress' );
1178
1179        // code to build arr
1180        $retArr = array();
1181
1182                // } This global holds "enabled/disabled" for specific fields... ignore unless you're WH or ask
1183                global $zbsFieldsEnabled;
1184    if ( $useSecondAddr == '1' ) {
1185        $zbsFieldsEnabled['secondaddress'] = true;
1186    }
1187
1188                // } This is the grouping :)
1189                $zbsFieldGroup = '';
1190    $zbsOpenGroup              = false;
1191
1192    foreach ( $fields as $fieldK => $fieldV ) {
1193
1194        $showField = true;
1195
1196        // } Check if not hard-hidden by opt override (on off for second address, mostly)
1197        if ( isset( $fieldV['opt'] ) && ( ! isset( $zbsFieldsEnabled[ $fieldV['opt'] ] ) || ! $zbsFieldsEnabled[ $fieldV['opt'] ] ) ) {
1198            $showField = false;
1199        }
1200
1201                    // or is hidden by checkbox?
1202        if ( isset( $fieldHideOverrides['customer'] ) && is_array( $fieldHideOverrides['customer'] ) ) {
1203            if ( in_array( $fieldK, $fieldHideOverrides['customer'] ) ) {
1204                $showField = false;
1205            }
1206        }
1207
1208                    // if show field :) add
1209        if ( $showField ) {
1210                $retArr[ $fieldK ] = $fieldV;
1211        }
1212    }
1213
1214        return $retArr;
1215}
1216
1217    // builds a detail array from post from form
1218    // the SAVE end to zeroBSCRM_html_editFields
1219    // centralisd/genericified 20/7/18 wh 2.91+
1220    // WH NOTE: This should be replaced/merged with buildObjArr
1221function zeroBSCRM_save_fields( $fieldArr = array(), $postKey = 'zbscq_', $skipFields = array() ) {
1222
1223    $res = array();
1224
1225    foreach ( $fieldArr as $fK => $fV ) {
1226
1227            $res[ $fK ] = '';
1228
1229        if ( isset( $_POST[ $postKey . $fK ] ) ) {
1230
1231            switch ( $fV[0] ) {
1232
1233                case 'tel':
1234                    // validate tel?
1235                    $res[ $fK ] = sanitize_text_field( $_POST[ $postKey . $fK ] );
1236                    preg_replace( '/[^0-9 ]/', '', $res[ $fK ] );
1237                    break;
1238
1239                case 'price':
1240                case 'numberfloat':
1241                    // validate price/float?
1242                    $res[ $fK ] = sanitize_text_field( $_POST[ $postKey . $fK ] );
1243                    $res[ $fK ] = preg_replace( '@[^0-9\.]+@i', '-', $res[ $fK ] );
1244                    $res[ $fK ] = floatval( $res[ $fK ] );
1245                    break;
1246
1247                case 'numberint':
1248                    // validate price?
1249                    $res[ $fK ] = sanitize_text_field( $_POST[ $postKey . $fK ] );
1250                    $res[ $fK ] = preg_replace( '@[^0-9]+@i', '-', $res[ $fK ] );
1251                    $res[ $fK ] = floatval( $res[ $fK ] );
1252                    break;
1253
1254                case 'textarea':
1255                    $res[ $fK ] = zeroBSCRM_textProcess( $_POST[ $postKey . $fK ] );
1256
1257                    break;
1258
1259                default:
1260                    $res[ $fK ] = sanitize_text_field( $_POST[ $postKey . $fK ] );
1261
1262                    break;
1263
1264            }
1265        }
1266    }
1267
1268    return $res;
1269}
1270
1271    /*
1272        zeroBSCRM_customFields_getSlugOrCreate
1273
1274            This function will get the slug for a custom field, based on a label, if it exists
1275            ... if it doesn't exist, it'll add it as a default text field type
1276
1277        params:
1278        $objectTypeStr='customers' | customersfiles | quotes | companies etc.
1279        $fieldLabel='Promotion URL' -
1280
1281        NOTE: only tested with 'customers' type - debug with others before production use
1282        NOTE: Not sure how early in the load-stack you can successfully use this.. to be tested
1283        NOTE: All custom field stuff should be centralised/refactored, this has got messy
1284
1285    */
1286function zeroBSCRM_customFields_getSlugOrCreate( $fieldLabel = '', $objectTypeStr = 'customers' ) {
1287
1288    // taken from admin pages custom fields:
1289    // standard custom fields processing (not files/any that need special treatment)
1290    // genericified 20/07/19 2.91
1291    $customFieldsToProcess = array(
1292        'addresses'    => 'zbsAddressFields',
1293        'customers'    => 'zbsCustomerFields',
1294        'companies'    => 'zbsCompanyFields',
1295        'quotes'       => 'zbsCustomerQuoteFields',
1296        'transactions' => 'zbsTransactionFields',
1297    );
1298
1299    // acceptable types
1300    $acceptableCFTypes = zeroBSCRM_customfields_acceptableCFTypes();
1301
1302    // block ID here too
1303    if ( ! empty( $fieldLabel ) && ! empty( $objectTypeStr ) && $fieldLabel != 'ID' && isset( $customFieldsToProcess[ $objectTypeStr ] ) ) {
1304
1305        global $wDB, $zbs;
1306
1307        $customFieldsArr = $zbs->settings->get( 'customfields' );
1308
1309        if (
1310            ( isset( $customFieldsArr[ $objectTypeStr ] ) && ! is_array( $customFieldsArr[ $objectTypeStr ] ) )
1311            ||
1312            ( ! isset( $customFieldsArr[ $objectTypeStr ] ) )
1313            ) {
1314            // set it (no real risk here, except for slap-handed-typos in $objectTypeStr)
1315            $customFieldsArr[ $objectTypeStr ] = array();
1316        }
1317
1318        // make slug
1319        $possSlug = $zbs->DAL->makeSlug( $fieldLabel );
1320
1321        // block ID here too
1322        if ( $possSlug !== 'id' ) {
1323
1324            // ====== TAKEN from adminpages custom fields saving
1325            // ... and modified a bit
1326            $globalVarName = $customFieldsToProcess[ $objectTypeStr ];
1327            // 2.96.7+ CHECK against existing fields + add -1 -2 etc. if already in there
1328
1329            // if exists, just return it :)
1330            if ( isset( $GLOBALS[ $globalVarName ][ $possSlug ] ) ) {
1331                return $possSlug;
1332            } else {
1333
1334                // doesn't exist, so add :)
1335
1336                    // make default vars
1337                    $possType        = 'text';
1338                    $possName        = $fieldLabel;
1339                    $possPlaceholder = '';
1340
1341                if ( in_array( $possType, $acceptableCFTypes ) ) {
1342
1343                    // } Add it
1344                    $customFieldsArr[ $objectTypeStr ][] = array( $possType, $possName, $possPlaceholder, $possSlug );
1345
1346                    // NOW SAVE DOWN
1347
1348                    if ( isset( $customFieldsArr['customers'] ) && is_array( $customFieldsArr['customers'] ) ) {
1349
1350                        // slight array reconfig
1351                        $db2CustomFields = array();
1352                        foreach ( $customFieldsArr['customers'] as $cfArr ) {
1353                            $db2CustomFields[ $zbs->DAL->makeSlug( $cfArr[1] ) ] = $cfArr;
1354                        }
1355
1356                        // simple maintain DAL2 (needs to also)
1357                        $zbs->DAL->updateActiveCustomFields(
1358                            array(
1359                                'objtypeid' => 1,
1360                                'fields'    => $db2CustomFields,
1361                            )
1362                        );
1363                    }
1364
1365                    // } Brutal update
1366                    $zbs->settings->update( 'customfields', $customFieldsArr );
1367
1368                    // update the fields/sorts so is reloaded in
1369                    zeroBSCRM_applyFieldSorts();
1370
1371                    return $possSlug;
1372                }
1373            }
1374        } // / is id
1375
1376    }
1377
1378    return false;
1379}
1380
1381function zeroBSCRM_customfields_acceptableCFTypes() {
1382
1383    return array(
1384        // all avail pre 2.98.5
1385        'text',
1386        'textarea',
1387        'date',
1388        'select',
1389        'tel',
1390        'price',
1391        'numberfloat',
1392        'numberint',
1393        'email',
1394        // 2.98.5
1395        'radio',
1396        'checkbox',
1397        'autonumber',
1398        // Removed encrypted (for now), see JIRA-ZBS-738
1399        // 'encrypted'
1400    );
1401}
1402
1403    // takes Strings from autonumber settings for prefix/suffix and parses some common replacements:
1404function zeroBSCRM_customFields_parseAutoNumberStr( $str = '' ) {
1405
1406    global $zbs;
1407
1408    // CURRENT DATE (on creation):
1409        // YYYY = 2019
1410        // YY = 19
1411        // MMMM = 01 - 12
1412        // MM = Jan - Dec
1413        // MONTH = January - December
1414        // WW = 01 - 52
1415        // DD = 01 - 31
1416        // DOY = 01 - 365
1417    // AGENT who's editing (on creation):
1418        // USEREMAIL = woody@gmail.com
1419        // USERID = 1
1420        // USERNAME = woodyhayday
1421        // USERINITIALS = WH
1422        // USERFULLNAME = Woody Hayday
1423        // USERFIRSTNAME = Woody
1424        // USERLASTNAME = Hayday
1425    $x = str_replace( 'YYYY', date( 'Y' ), $str );
1426    $x = str_replace( 'YY', date( 'y' ), $x );
1427    $x = str_replace( 'MMMM', date( 'm' ), $x );
1428    $x = str_replace( 'MM', date( 'M' ), $x );
1429    $x = str_replace( 'MONTH', date( 'F' ), $x );
1430    $x = str_replace( 'WW', date( 'W' ), $x );
1431    $x = str_replace( 'DD', date( 'd' ), $x );
1432    $x = str_replace( 'DOY', date( 'z' ), $x );
1433
1434    // User Prefix
1435    $userID = $zbs->user();
1436    if ( $userID > 0 ) {
1437            $user_info = get_userdata( $zbs->user() );
1438            $x         = str_replace( 'USEREMAIL', $user_info->user_email, $x );
1439            $x         = str_replace( 'USERID', $userID, $x );
1440            $x         = str_replace( 'USERNAME', $user_info->user_login, $x );
1441            $initials  = '';
1442        if ( isset( $user_info->first_name ) && ! empty( $user_info->first_name ) ) {
1443            $initials .= substr( trim( $user_info->first_name ), 0, 1 );
1444        }
1445        if ( isset( $user_info->last_name ) && ! empty( $user_info->last_name ) ) {
1446            $initials .= substr( trim( $user_info->last_name ), 0, 1 );
1447        }
1448            $x = str_replace( 'USERINITIALS', strtoupper( $initials ), $x );
1449            $x = str_replace( 'USERFULLNAME', $user_info->first_name . ' ' . $user_info->last_name, $x );
1450            $x = str_replace( 'USERFIRSTNAME', $user_info->first_name, $x );
1451            $x = str_replace( 'USERLASTNAME', $user_info->last_name, $x );
1452    } else {
1453
1454        // replace for those where no username etc. (API)
1455        $x = str_replace( 'USEREMAIL', '', $x );
1456        $x = str_replace( 'USERID', '', $x );
1457        $x = str_replace( 'USERNAME', '', $x );
1458        $x = str_replace( 'USERINITIALS', '', $x );
1459        $x = str_replace( 'USERFULLNAME', '', $x );
1460        $x = str_replace( 'USERFIRSTNAME', '', $x );
1461        $x = str_replace( 'USERLASTNAME', '', $x );
1462    }
1463
1464    return $x;
1465}
1466
1467    // retrieves a number from current custom field setting (autonumber)
1468    // ... returns it + ups the number in the custom field setting
1469    // this may be called several times if updating many, but tiny unperformant bit should be worth it
1470    // ... for the safety of double checking
1471function zeroBSCRM_customFields_getAutoNumber( $objTypeID = -1, $fK = '' ) {
1472
1473    global $zbs;
1474
1475    // def
1476    $return = false;
1477
1478    // see if exists (get custom fields for obj)
1479    $customFields = $zbs->DAL->getActiveCustomFields( array( 'objtypeid' => $objTypeID ) );
1480
1481    // we have to do this in a way which feels very dangerous.
1482    // we take the custom field setting to bits and rebuild with incremented autonumber.
1483    // these should be moved to their own safer system/table, I think. v3.1?
1484    if ( is_array( $customFields ) && count( $customFields ) > 0 ) {
1485
1486            // this'll be replaced by all array items, with the autonumber upped, all being well
1487            // legacy pain.
1488            $newCustomFields = array();
1489        $changed             = false;
1490
1491            // eeeeish these aren't even array keyed. legacy pain.
1492        foreach ( $customFields as $f ) {
1493
1494            $added = false;
1495
1496            // f3 = slug
1497            if ( is_array( $f ) && isset( $f[3] ) && $f[3] == $fK && $f[0] == 'autonumber' ) {
1498
1499                    // this is our autonumber.
1500
1501                        // split it
1502                        $autonumber = explode( '#', $f[2] );
1503                if ( count( $autonumber ) == 3 ) {
1504
1505                    // all seems well, will be prefix,number,suffix
1506                    $no = (int) trim( $autonumber[1] );
1507
1508                    if ( $no > -1 ) {
1509
1510                                // great, got a number of at least 0
1511
1512                                    // set return
1513                                    $return = $no;
1514
1515                                    // increment
1516                                    ++$no;
1517
1518                                    // add back in, with incremented autonumber
1519                                    $newCustomField    = $f;
1520                                    $newCustomField[2] = $autonumber[0] . '#' . $no . '#' . $autonumber[2];
1521                                    $newCustomFields[] = $newCustomField;
1522                                    $added             = true;
1523                                    $changed           = true;
1524
1525                    }
1526                }
1527            }
1528
1529            // not added by above?
1530            if ( ! $added ) {
1531
1532                    // just make sure still in array
1533                    $newCustomFields[] = $f;
1534
1535            }
1536        }
1537
1538            // save down (if changed)
1539        if ( $changed ) {
1540
1541            if ( is_array( $newCustomFields ) ) {
1542
1543                    // slight array reconfig
1544                    $db2CustomFields = array();
1545                foreach ( $newCustomFields as $cfArr ) {
1546                    $db2CustomFields[ $zbs->DAL->makeSlug( $cfArr[1] ) ] = $cfArr;
1547                }
1548
1549                    // simple maintain DAL2 (needs to also)
1550                    $zbs->DAL->updateActiveCustomFields(
1551                        array(
1552                            'objtypeid' => $objTypeID,
1553                            'fields'    => $db2CustomFields,
1554                        )
1555                    );
1556
1557            }
1558        }
1559    } // / if custom fields
1560
1561    return $return;
1562}
1563
1564    // unpacks csv options and sets 'custom-field' attr
1565    // (used in several places so unifying)
1566function zeroBSCRM_customFields_processCustomField( $fieldOrig = false ) {
1567
1568    // split
1569    $fieldO = $fieldOrig;
1570
1571    if ( is_array( $fieldO ) ) {
1572
1573        // } unpack csv
1574        if ( $fieldO[0] == 'select' || $fieldO[0] == 'checkbox' || $fieldO[0] == 'radio' ) {
1575
1576            // } Legacy shiz? needed post dal2?
1577            // } This gives empty placeholder and exploded original str
1578            if ( isset( $fieldO[3] ) && ! is_array( $fieldO[3] ) ) {
1579                $fieldO[2] = '';
1580                $fieldO[3] = explode( ',', $fieldOrig[2] );
1581            }
1582        }
1583
1584        // here we set a flag that defines them as custom fields
1585        $fieldO['custom-field'] = true;
1586
1587        return $fieldO;
1588
1589    }
1590
1591    return false;
1592}
1593
1594    /*
1595    example: getActiveCustomFields
1596
1597
1598    "customers": [
1599        ["text", "filename", "Filename", "filename"],
1600        ["date", "dddd", "", "dddd"],
1601        ["select", "selecter", "a,b,c", "selecter"],
1602        ["radio", "radioz", "rad1,rad2,rad3,rad4,rad5,rad6,rad7,rad89,another option,andmore,and this,oh and don\\'t forget", "radioz"],
1603        ["checkbox", "check boz", "checkbox,afeafhte,another check,last one!", "check-boz"],
1604        ["autonumber", "autonumbz", "zzAAAX#12343#zzXXXX", "autonumbz"],
1605        ["numberint", "forced numeric", "999", "forced-numeric"],
1606        ["radio", "empty radio", "", "empty-radio"],
1607        ["checkbox", "empty check", "", "empty-check"],
1608        ["select", "empty select", "", "empty-select"]
1609    ],
1610
1611    */
1612/*
1613======================================================
1614    / Field Helper funcs
1615    ====================================================== */