Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 179
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
zeroBSCRM_Edit
0.00% covered (danger)
0.00%
0 / 178
0.00% covered (danger)
0.00%
0 / 8
4692
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
650
 loadObject
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
42
 catchPost
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 preChecks
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
306
 preCheckFail
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 post_learn_menu_output
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 drawEditView
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 drawEditViewHTML
0.00% covered (danger)
0.00%
0 / 81
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2/*
3 * Jetpack CRM
4 * https://jetpackcrm.com
5 * V2.52+
6 *
7 * Copyright 2020 Automattic
8 *
9 * Date: 26/02/18
10 */
11
12defined( 'ZEROBSCRM_PATH' ) || exit( 0 );
13
14class zeroBSCRM_Edit {
15
16    private $objID     = false;
17    private $obj       = false;
18    private $objTypeID = false; // ZBS_TYPE_CONTACT - v3.0+
19
20    // following now FILLED OUT by objTypeID above, v3.0+
21    private $objType  = false; // 'contact'
22    private $singular = false;
23    private $plural   = false;
24    // renamed listViewSlug v3.0+ private $postPage = false;
25    private $listViewSlug = false;
26
27    private $langLabels    = false;
28    private $bulkActions   = false;
29    private $sortables     = false;
30    private $unsortables   = false;
31    private $extraBoxes    = '';
32    private $isGhostRecord = false;
33    private $isNewRecord   = false;
34
35    // permissions
36    private $has_permissions_to_edit = false;
37
38    function __construct( $args = array() ) {
39
40        #} =========== LOAD ARGS ==============
41        $defaultArgs = array(
42
43            'objID'        => false,
44            'objTypeID'    => false,   // 5
45
46            // these are now retrieved from DAL centralised vars by objTypeID above, v3.0+
47            // ... unless hard typed here.
48            'objType'      => false,   // transaction
49            'singular'     => false,  // Transaction
50            'plural'       => false,      // Transactions
51            'listViewSlug' => false,    // manage-transactions
52
53            'langLabels'   => array(),
54            'extraBoxes'   => '', // html for extra boxes e.g. upsells :)
55
56        );
57        foreach ( $defaultArgs as $argK => $argV ) {
58            $this->$argK = $argV;
59            if ( is_array( $args ) && isset( $args[ $argK ] ) ) {
60                if ( is_array( $args[ $argK ] ) ) {
61                    $newData = $this->$argK;
62                    if ( ! is_array( $newData ) ) {
63                        $newData = array();
64                    } foreach ( $args[ $argK ] as $subK => $subV ) {
65                        $newData[ $subK ] = $subV;
66                    }$this->$argK = $newData;
67                } else {
68                    $this->$argK = $args[ $argK ]; }
69            }
70        }
71        #} =========== / LOAD ARGS =============
72
73        // NOTE: here these vars are passed like:
74        // $this->objID
75        // .. NOT
76        // $objID
77
78        global $zbs;
79
80        // we load from DAL defaults, if objTypeID passed (overriding anything passed, if empty/false)
81        if ( isset( $this->objTypeID ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
82
83            $objTypeID = (int) $this->objTypeID;
84            if ( $objTypeID > 0 ) {
85
86                // obj type (contact)
87                $objTypeStr = $zbs->DAL->objTypeKey( $objTypeID );
88                if ( ( ! isset( $this->objType ) || $this->objType == false ) && ! empty( $objTypeStr ) ) {
89                    $this->objType = $objTypeStr;
90                }
91
92                // singular
93                $objSingular = $zbs->DAL->typeStr( $objTypeID );
94                if ( ( ! isset( $this->singular ) || $this->singular == false ) && ! empty( $objSingular ) ) {
95                    $this->singular = $objSingular;
96                }
97
98                // plural
99                $objPlural = $zbs->DAL->typeStr( $objTypeID, true );
100                if ( ( ! isset( $this->plural ) || $this->plural == false ) && ! empty( $objPlural ) ) {
101                    $this->plural = $objPlural;
102                }
103
104                // listViewSlug
105                $objSlug = $zbs->DAL->listViewSlugFromObjID( $objTypeID );
106                if ( ( ! isset( $this->listViewSlug ) || $this->listViewSlug == false ) && ! empty( $objSlug ) ) {
107                    $this->listViewSlug = $objSlug;
108                }
109            }
110        } else {
111            $this->isNewRecord = true;
112        }
113
114        // if objid - load $post
115        $this->loadObject();
116
117        // Ghost?
118        if ( $this->objID !== -1 && ! $this->isNewRecord && isset( $this->objTypeID ) && ! is_array( $this->obj ) ) {
119            $this->isGhostRecord = true;
120        }
121
122        // anything to save?
123        $this->catchPost();
124
125        // include any 'post learn menu' code
126        add_action( 'zerobscrm-subtop-menu', array( $this, 'post_learn_menu_output' ) );
127    }
128
129    // automatically, generically, loads the single obj
130    public function loadObject() {
131
132        // if objid - load $post
133        if ( isset( $this->objID ) && ! empty( $this->objID ) && $this->objID > 0 ) {
134
135            global $zbs;
136
137            if ( $this->objTypeID > 0 ) {
138
139                // got permissions?
140                if ( zeroBSCRM_permsObjType( $this->objTypeID ) ) {
141
142                    // this gets $zbs->DAL->contacts->getSingle()
143                    $this->obj = $zbs->DAL->getObjectLayerByType( $this->objTypeID )->getSingle( $this->objID );
144
145                    // has permissions
146                    $this->has_permissions_to_edit = true;
147
148                }
149            }
150        }
151    }
152
153    public function catchPost() {
154
155        // If post, fire do_action
156        if ( isset( $_POST['zbs-edit-form-master'] ) && $_POST['zbs-edit-form-master'] == $this->objType ) {
157
158            // make sure we have perms to save
159            if ( $this->preChecks() ) {
160                // fire it
161                do_action( 'zerobs_save_' . $this->objType, $this->objID, $this->obj );
162                // after catching post, we need to reload data :) (as may be changed)
163                $this->loadObject();
164            }
165        }
166    }
167
168    // check ownership, access etc.
169    public function preChecks() {
170
171        global $zbs;
172
173        $is_malformed_obj = false;
174
175        if ( is_array( $this->obj ) && isset( $this->obj['owner'] ) ) {
176            $obj_owner = (int) $this->obj['owner'];
177
178                // Transactions can have a contact or company assigned, and quotes just a contact. This covers checking owners for both.
179            if ( isset( $this->obj['contact'][0]['owner'] ) ) {
180                    $obj_owner = (int) $this->obj['contact'][0]['owner'];
181
182            } elseif ( isset( $this->obj['company'][0]['owner'] ) ) {
183                $obj_owner = (int) $this->obj['company'][0]['owner'];
184            }
185
186            // This covers checking owners for assigned contacts or companies in invoices.
187            if ( $this->objTypeID === ZBS_TYPE_INVOICE ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
188                $data = zeroBSCRM_invoicing_getInvoiceData( $this->objID ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
189                if ( ! empty( $data['invoiceObj']['contact'] ) ) {
190                    $obj_owner = (int) $data['invoiceObj']['contact'][0]['owner'];
191                } elseif ( ! empty( $data['invoiceObj']['company'] ) ) {
192                    $obj_owner = (int) $data['invoiceObj']['company'][0]['owner'];
193                }
194            }
195        } else {
196            // if $this->obj is not an array, somehow it's not been loaded properly (probably perms)
197            // get owner info anyway
198            $is_malformed_obj = true;
199            $obj_owner        = $zbs->DAL->getObjectOwner( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
200                array(
201                    'objID'     => $this->objID, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
202                    'objTypeID' => $this->objTypeID, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
203                )
204            );
205        }
206        // get current user
207        $current_user_id = get_current_user_id();
208
209        if ( $obj_owner > 0 && $obj_owner != $current_user_id || $obj_owner == -1 ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual,Universal.Operators.StrictComparisons.LooseEqual -- see below.
210                // not current user
211                // does user have perms to edit?
212                $can_edit_all_contacts = current_user_can( 'admin_zerobs_customers' ) && $zbs->settings->get( 'perusercustomers' ) == 0; // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual,WordPress.WP.Capabilities.Unknown  -- this was defined in ZeroBSCRM.Permissions.php.
213                $can_give_ownership    = $zbs->settings->get( 'usercangiveownership' ) == 1; // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual -- also above, there is the chance the numbers could be strings here, as expected elsewhere in the plugin.
214                $can_change_owner      = ( $can_give_ownership || current_user_can( 'manage_options' ) || $can_edit_all_contacts );
215
216            if ( ! $can_change_owner ) {
217
218                    // owners can't be changed with user's perms, so denied msg
219                    // Translators: %s is the object type (for example transaction, quote, invoice).
220                    $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
221                    return false;
222
223            }
224            if ( ! $this->has_permissions_to_edit ) {
225                // user does not have a role which can edit this object type
226                $this->preCheckFail( sprintf( __( 'You do not have permission to edit this %s.', 'zero-bs-crm' ), $zbs->DAL->typeStr( $this->objTypeID ) ) );
227                return false;
228
229            }
230            if ( $is_malformed_obj ) {
231                // not a perms issue, so show general error
232                $this->preCheckFail( sprintf( __( 'There was an error loading this %s.', 'zero-bs-crm' ), $zbs->DAL->typeStr( $this->objTypeID ) ) );
233                return false;
234            }
235        }
236
237        // load if is legit
238        return true;
239    }
240
241    public function preCheckFail( $msg = '' ) {
242
243            echo '<div id="zbs-obj-edit-precheck-fail" class="ui grid"><div class="row"><div class="two wide column"></div><div class="twelve wide column">';
244            echo zeroBSCRM_UI2_messageHTML( 'warning', $msg, '', 'disabled warning sign', 'failRetrieving' );
245            echo '</div></div>';
246
247            // grim quick hack to hide save button
248            echo '<style>#zbs-edit-save{display:none}</style>';
249    }
250
251    /*
252    *  Code added to this function will be called just after the learn menu is output
253    *  (where we're on an edit page)
254    */
255    public function post_learn_menu_output() {
256
257        // put screen options out
258        zeroBSCRM_screenOptionsPanel();
259    }
260
261    public function drawEditView() {
262
263        // run pre-checks which verify ownership etc.
264        $okayToDraw = $this->preChecks();
265
266        // draw if okay :)
267        if ( $okayToDraw ) {
268            $this->drawEditViewHTML();
269        }
270    }
271
272    public function drawEditViewHTML() {
273
274        if ( empty( $this->objType ) || empty( $this->listViewSlug ) || empty( $this->singular ) || empty( $this->plural ) ) {
275
276            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' );
277            return false;
278
279        }
280
281        // catch id's passed where no contact exists for them.
282        if ( $this->isGhostRecord ) {
283
284            // brutal hide, then msg #ghostrecord
285            ?><style type="text/css">#zbs-edit-save, #zbs-nav-view, #zbs-nav-prev, #zbs-nav-next { display:none; }</style>
286            <div id="zbs-edit-warnings-wrap">
287            <?php
288            echo zeroBSCRM_UI2_messageHTML( 'warning', 'Error Retrieving ' . $this->singular, 'There does not appear to be a ' . $this->singular . ' with this ID.', 'disabled warning sign', 'zbsCantLoadData' );
289            ?>
290            </div>
291            <?php
292            return false;
293
294        }
295
296        // catch if is new record + hide zbs-nav-view
297        if ( $this->isNewRecord ) {
298
299            // just hide button via css. Should just stop this via learn in time
300            ?>
301            <style type="text/css">#zbs-nav-view { display:none; }</style>
302            <?php
303
304        }
305
306        global $zbs;
307
308        // run pre-checks which verify ownership etc.
309        $this->preChecks();
310
311        ?>
312        <div id="zbs-edit-master-wrap"><form method="post" id="zbs-edit-form" enctype="multipart/form-data"><input type="hidden" name="zbs-edit-form-master" value="<?php echo esc_attr( $this->objType ); ?>" />
313
314            <div id="zbs-edit-warnings-wrap">
315                <?php
316                #} Pre-loaded msgs, because I wrote the helpers in php first... should move helpers to js and fly these
317
318                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' );
319                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' );
320
321                ?>
322            </div>
323            <!-- main view: list + sidebar -->
324            <div id="zbs-edit-wrap" class="ui divided grid <?php echo 'zbs-edit-wrap-' . esc_attr( $this->objType ); ?>">
325
326                <?php
327
328                if ( count( $zbs->pageMessages ) > 0 ) {
329
330                    #} Updated Msgs
331                    // was doing like this, but need control over styling
332                    // do_action( 'zerobs_updatemsg_contact');
333                    // so for now just using global :)
334                    echo '<div class="row" style="padding-bottom: 0 !important;" id="zbs-edit-notification-row"><div class="sixteen wide column" id="zbs-edit-notification-wrap">';
335
336                    foreach ( $zbs->pageMessages as $msg ) {
337
338                        // for now these can be any html :)
339                        echo $msg;
340
341                    }
342
343                        echo '</div></div>';
344
345                }
346
347                ?>
348
349                <div class="row">
350
351
352                    <!-- record list -->
353                    <div class="twelve wide column" id="zbs-edit-table-wrap">
354
355                        <?php
356                            #} Main Metaboxes
357                            zeroBSCRM_do_meta_boxes( 'zbs-add-edit-' . $this->objType . '-edit', 'normal', $this->obj );
358                        ?>
359
360                    </div>
361                    <!-- side bar -->
362                    <div class="four wide column" id="zbs-edit-sidebar-wrap">
363                        <?php
364
365                            #} Sidebar metaboxes
366                            zeroBSCRM_do_meta_boxes( 'zbs-add-edit-' . $this->objType . '-edit', 'side', $this->obj );
367
368                        ?>
369
370                        <?php ##WLREMOVE ?>
371                        <?php echo $this->extraBoxes; ?>
372                        <?php ##/WLREMOVE ?>
373                    </div>
374                </div>
375
376                <!-- could use this for mobile variant?) 
377                <div class="two column mobile only row" style="display:none"></div>
378                -->
379            </div> <!-- / mainlistview wrap -->
380        </form></div>
381
382        <script type="text/javascript">
383
384            jQuery(function($){
385
386                console.log("======= EDIT VIEW UI =========");
387                
388                jQuery('.show-more-tags').on("click",function(e){
389                    jQuery('.more-tags').show();
390                    jQuery(this).hide();
391                });
392
393            });
394
395            // General options for edit page
396            var zbsEditSettings = {
397
398                objid: <?php echo esc_js( $this->objID ); ?>,
399                objdbname: '<?php echo esc_js( $this->objType ); ?>',
400                nonce: '<?php echo esc_js( wp_create_nonce( 'edit-nonce-' . $this->objType ) ); ?>'
401
402            };
403            var zbsDrawEditViewBlocker = false;
404            var zbsDrawEditAJAXBlocker = false;
405
406            <?php // these are all legacy, move over to zeroBSCRMJS_obj_editLink in global js: ?>
407            var zbsObjectViewLinkPrefixCustomer = '<?php echo jpcrm_esc_link( 'view', -1, 'zerobs_customer', true ); ?>';
408            var zbsObjectEditLinkPrefixCustomer = '<?php echo jpcrm_esc_link( 'edit', -1, 'zerobs_customer', true ); ?>';
409            var zbsObjectViewLinkPrefixCompany = '<?php echo jpcrm_esc_link( 'view', -1, 'zerobs_company', true ); ?>';
410            var zbsListViewLink = '<?php echo jpcrm_esc_link( $this->listViewSlug ); ?>';
411
412            
413            var zbsClick2CallType = parseInt('<?php echo esc_html( zeroBSCRM_getSetting( 'clicktocalltype' ) ); ?>');
414            var zbsEditViewLangLabels = {
415
416                    'today': '<?php echo esc_html( zeroBSCRM_slashOut( __( 'Today', 'zero-bs-crm' ) ) ); ?>',
417                    'view': '<?php echo esc_html( zeroBSCRM_slashOut( __( 'View', 'zero-bs-crm' ) ) ); ?>',
418                    'contact': '<?php echo esc_html( zeroBSCRM_slashOut( __( 'Contact', 'zero-bs-crm' ) ) ); ?>',
419                    'company': '<?php echo esc_html( zeroBSCRM_slashOut( jpcrm_label_company() ) ); ?>',
420
421                    <?php
422                    $labelCount = 0;
423                    if ( count( $this->langLabels ) > 0 ) {
424                        foreach ( $this->langLabels as $labelK => $labelV ) {
425
426                            if ( $labelCount > 0 ) {
427                                echo ',';
428                            }
429
430                            echo esc_html( $labelK ) . ":'" . esc_html( zeroBSCRM_slashOut( $labelV, true ) ) . "'";
431
432                            ++$labelCount;
433
434                        }
435                    }
436                    ?>
437
438            };
439            <?php
440            #} Nonce for AJAX
441                    echo "var zbscrmjs_secToken = '" . esc_js( wp_create_nonce( 'zbscrmjs-ajax-nonce' ) ) . "';";
442            ?>
443                    </script>
444                    <?php
445    } // /draw func
446} // class