Completed
Push — master ( f71c82...1db67b )
by
unknown
03:31
created

EcommerceTaskMigration::orderTax_45()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
dl 0
loc 45
rs 7.6444
c 0
b 0
f 0
nc 9
nop 0
1
<?php
2
3
4
/**
5
 * @description: migrates older versions of e-commerce to the latest one.
6
 * This has been placed here rather than in the individual classes for the following reasons:
7
 * - not to clog up individual classes
8
 * - to get a complete overview in one class
9
 * - to be able to run parts and older and newer version without having to go through several clases to retrieve them
10
 *
11
 * @authors: Nicolaas [at] Sunny Side Up .co.nz
12
 * @package: ecommerce
13
 * @sub-package: tasks
14
 * @inspiration: Silverstripe Ltd, Jeremy
15
 * @todo: change methods to simple names f10, f20, etc... and then allow individual ones to be run.
16
 * @todo: 200 + 210 need attention.
17
 **/
18
class EcommerceTaskMigration extends BuildTask
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
19
{
20
    protected $limit = 300;
21
22
    protected $start = 0;
23
24
    protected $retrieveInfoOnly = false;
25
26
    protected $title = 'Ecommerce Migration';
27
28
    protected $description = '
29
        Migrates all the data from the oldest version of e-commerce to the current one.
30
        Any obsolete fields will be renamed like this: _obsolete_MyField, but not deleted.
31
    ';
32
33
    protected $listOfMigrationTasks = array(
34
        'shopMemberToMemberTableMigration_10',
35
        'moveItemToBuyable_20',
36
        'productVersionToOrderItem_25',
37
        'productIDToBuyableID_26',
38
        'amountToCalculatedTotal_27',
39
        'currencyToMoneyFields_30',
40
        'orderShippingCost_40',
41
        'orderTax_45',
42
        'orderShippingAddress_50',
43
        'orderBillingAddress_51',
44
        'memberBillingAddress_52',
45
        'moveOrderStatus_60',
46
        'fixBadOrderStatus_68',
47
        'updateProductGroups_110',
48
        'setFixedPriceForSubmittedOrderItems_120',
49
        'moveSiteConfigToEcommerceDBConfig_140',
50
        'addClassNameToOrderItems_150',
51
        'addTermsAndConditionsMessage_160',
52
        'mergeUncompletedOrderForOneMember_170',
53
        'updateFullSiteTreeSortFieldForAllProducts_180',
54
        'updateOrderStatusLogSequentialOrderNumber_190',
55
        'resaveAllPRoducts_200',
56
        'resaveAllPRoductsVariations_210',
57
        'addConfirmationPage_250',
58
        'cleanupImages_260',
59
        'addNewPopUpManager_280',
60
        'addCurrencyCodeIDToOrders_290',
61
        'MovePaymentToEcommercePayment_300',
62
        'ecommercetaskupgradepickupordeliverymodifier_310',
63
        'ecommercetaskupgradepickupordeliverymodifier_320',
64
        'removemobilephones_330',
65
        'theEnd_9999',
66
    );
67
68
    public function run($request)
0 ignored issues
show
Coding Style introduced by
run uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
69
    {
70
        set_time_limit(1200);
71
        increase_memory_limit_to(-1);
72
        $nextGetStatement = '';
73
        //can we do the next step?
74
        //IN general yes, but if the current one is not finished yet, then we do it again.
75
        $canDoNext = true;
76
        if (isset($_REQUEST['limit'])) {
77
            $this->limit = intval($_REQUEST['limit']);
78
        }
79
        if (isset($_REQUEST['start'])) {
80
            $this->start = intval($_REQUEST['start']);
81
        }
82
83
        //what is the current step?
84
        $currentMethod = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
85
        if (in_array($currentMethod, $this->listOfMigrationTasks)) {
86
87
            //are we doing the same one for a different limti?
88
            if ($this->start) {
89
                $this->DBAlterationMessageNow('this task is broken down into baby steps - we are now starting at .... '.$this->start.' processing '.$this->limit, 'created');
90
            }
91
            $nextLimit = $this->$currentMethod();
92
            if ($canDoNext && $nextLimit) {
93
                $canDoNext = false;
94
                //NEXT OPTION 1: do again with new limit
95
                $nextGetStatement = '?action='.$currentMethod.'&start='.$nextLimit;
96
                $nextDescription = 'run next batch ...';
97
            }
98
        }
99
100
        if ($canDoNext && !$nextGetStatement) {
101
            //NEXT OPTION 2: start from the beginning
102
            $nextGetStatement = '?fullmigration=1&action='.$this->listOfMigrationTasks[0];
103
            $nextDescription = "Start Migration by clicking on <i>'Next'</i> (this link) until all tasks have been completed.";
104
        }
105
        //retrieve data...
106
        $this->retrieveInfoOnly = true;
107
        $html = '';
108
        $createListOfActions = false;
109
        if (!$currentMethod) {
110
            $createListOfActions = true;
111
        }
112
        if ($createListOfActions) {
113
            $html .= '
114
            <p>Always make a backup of your database before running any migration tasks.</p>
115
            <ul>';
116
        }
117
        foreach ($this->listOfMigrationTasks as $key => $task) {
118
            $explanation = $this->$task();
119
            $explanation = str_replace(array('<h1>', '</h1>', '<p>', '</p>'), array('<strong>', '</strong>: ', '<span style="color: grey;">', '</span>'), $explanation);
120
            if ($task == $currentMethod) {
121
                if ($canDoNext) {
122
                    $keyPlusOne = $key + 1;
123
                    if (isset($this->listOfMigrationTasks[$keyPlusOne]) && isset($_REQUEST['fullmigration'])) {
124
                        //NEXT OPTION 3: next action!
125
                        $action = $this->listOfMigrationTasks[$keyPlusOne];
126
                        $nextGetStatement = '?action='.$action;
127
                        $nextDescription = $this->$action();
128
                        $nextDescription = str_replace(array('<h1>', '</h1>', '<p>', '</p>'), array('<strong>', '</strong>: ', '<span style="color: grey;">', '</span>'), $nextDescription);
129
                    } else {
130
                        //NEXT OPTION 4: we have done all of them - no more next option...
131
                        $nextGetStatement = '';
132
                        $nextDescription = '';
133
                    }
134
                }
135
            }
136
            if ($createListOfActions) {
137
                $html .=  '<li><a href="/dev/ecommerce/ecommercetaskmigration/?action='.$task."\">$explanation </a></li>";
138
            }
139
        }
140
        if ($createListOfActions) {
141
            $html .= '</ul>';
142
        }
143
        if ($nextGetStatement) {
144
            $nextLink = '/dev/ecommerce/ecommercetaskmigration/'.$nextGetStatement;
145
            if (isset($_REQUEST['fullmigration'])) {
146
                $nextLink .= '&fullmigration=1';
147
            }
148
            echo "
149
                <hr style=\"margin-top: 50px;\"/>
150
                <h3><a href=\"$nextLink\">NEXT: $nextDescription</a></h3>";
0 ignored issues
show
Bug introduced by
The variable $nextDescription does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
151
            if ($currentMethod) {
152
                echo "
153
                <div style=\"width: 400px; height: 20px; padding-top: 20px; font-size: 11px; background: url(/ecommerce/images/loading.gif) no-repeat top left transparent\">
154
                    Next step, if any - will load automatically in ten seconds.
155
                </div>
156
                <script type=\"text/javascript\">
157
                    var t = window.setTimeout(
158
                        function(){
159
                            window.location = '$nextLink';
160
                        },
161
                        500
162
                    );
163
                </script>
164
                <hr style=\"margin-bottom: 500px;\"/>
165
            ";
166
            }
167
        }
168
        echo $html;
169
    }
170
171
    /**
172
     * Returns true if the table and field (within this table) exist.
173
     * Otherwise it returns false.
174
     *
175
     * @param string - $field - name of the field to be tested
176
     * @param string - $table - name of the table to be tested
177
     *
178
     * @return bool
179
     */
180
    protected function hasTableAndField($table, $field)
181
    {
182
        $db = DB::getConn();
0 ignored issues
show
Deprecated Code introduced by
The method DB::getConn() has been deprecated with message: since version 4.0 Use DB::get_conn instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
183
        if ($db->hasTable($table)) {
0 ignored issues
show
Deprecated Code introduced by
The method SS_Database::hasTable() has been deprecated with message: since version 4.0 Use DB::get_schema()->hasTable() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
184
            $fieldArray = $db->fieldList($table);
0 ignored issues
show
Deprecated Code introduced by
The method SS_Database::fieldList() has been deprecated with message: since version 4.0 Use DB::field_list instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
185
            if (isset($fieldArray[$field])) {
186
                return true;
187
            }
188
        }
189
190
        return false;
191
    }
192
193
    /**
194
     * Returns true if the table and field (within this table) exist.
195
     * Otherwise it returns false.
196
     *
197
     * @param string - $field - name of the field to be tested
198
     * @param string - $table - name of the table to be tested
199
     *
200
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
201
     */
202
    protected function makeFieldObsolete($table, $field, $format = '')
0 ignored issues
show
Unused Code introduced by
The parameter $format is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
203
    {
204
        if ($this->hasTableAndField($table, $field)) {
205
            $db = DB::getConn();
0 ignored issues
show
Deprecated Code introduced by
The method DB::getConn() has been deprecated with message: since version 4.0 Use DB::get_conn instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
206
            $db->dontRequireField($table, $field);
0 ignored issues
show
Deprecated Code introduced by
The method SS_Database::dontRequireField() has been deprecated with message: since version 4.0 Use DB::dont_require_field() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
207
            $this->DBAlterationMessageNow("removed $field from $table", 'deleted');
208
        } else {
209
            $this->DBAlterationMessageNow("ERROR: could not find $field in $table so it could not be removed", 'deleted');
210
        }
211
        if ($this->hasTableAndField($table, $field)) {
212
            $this->DBAlterationMessageNow("ERROR: tried to remove $field from $table but it still seems to be there", 'deleted');
213
        }
214
    }
215
216
    protected function shopMemberToMemberTableMigration_10()
217
    {
218
        $explanation = '
219
            <h1>10. ShopMember to Member</h1>
220
            <p>In the first version of e-commerce we had the ShopMember class, then we moved this data to Member.</p>
221
        ';
222
        if ($this->retrieveInfoOnly) {
223
            return $explanation;
224
        } else {
225
            echo $explanation;
226
        }
227
        if ($this->hasTableAndField('ShopMember', 'ID')) {
228
            $exist = DB::query("SHOW TABLES LIKE 'ShopMember'")->numRecords();
229
            if ($exist > 0) {
230
                DB::query("
231
                    UPDATE \"Member\", \"ShopMember\"
232
                    SET
233
                        \"Member\".\"ClassName\" = 'Member',
234
                        \"Member\".\"Address\" = \"ShopMember\".\"Address\",
235
                        \"Member\".\"AddressLine2\" = \"ShopMember\".\"AddressLine2\",
236
                        \"Member\".\"City\" = \"ShopMember\".\"City\",
237
                        \"Member\".\"State\" = \"ShopMember\".\"State\",
238
                        \"Member\".\"Country\" = \"ShopMember\".\"Country\",
239
                        \"Member\".\"Notes\" = \"ShopMember\".\"Notes\"
240
                    WHERE \"Member\".\"ID\" = \"ShopMember\".\"ID\"
241
                ");
242
                $this->DBAlterationMessageNow('Successfully migrated ShopMember To Member.', 'created');
243
            } else {
244
                $this->DBAlterationMessageNow('No need to migrate ShopMember To Member because it does not have any records.');
245
            }
246
            DB::query('DROP TABLE "ShopMember";');
247
        } else {
248
            $this->DBAlterationMessageNow('There is no need to migrate the ShopMember table.');
249
        }
250
    }
251
252
    protected function moveItemToBuyable_20()
253
    {
254
        $explanation = '
255
            <h1>20. Move ItemID to Buyable</h1>
256
            <p>Move the Product ID in OrderItem as ItemID to a new field called BuyableID.</p>
257
        ';
258
        if ($this->retrieveInfoOnly) {
259
            return $explanation;
260
        } else {
261
            echo $explanation;
262
        }
263
        if ($this->hasTableAndField('OrderItem', 'ItemID')) {
264
            DB::query('
265
                UPDATE "OrderItem"
266
                SET "OrderItem"."BuyableID" = "OrderItem"."ItemID"
267
                WHERE "BuyableID" = 0 OR "BuyableID" IS NULL
268
            ');
269
            $this->makeFieldObsolete('OrderItem', 'ItemID');
270
            $this->DBAlterationMessageNow('Moved ItemID to BuyableID in OrderItem', 'created');
271
        } else {
272
            $this->DBAlterationMessageNow('There is no need to move from ItemID to BuyableID');
273
        }
274
    }
275
276
    protected function productVersionToOrderItem_25()
277
    {
278
        $explanation = '
279
            <h1>25. ProductVersion to Version</h1>
280
            <p>Move the product version in the Product_OrderItem table to the OrderItem table.</p>
281
        ';
282
        if ($this->retrieveInfoOnly) {
283
            return $explanation;
284
        } else {
285
            echo $explanation;
286
        }
287
        $table = 'LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL';
288
        if ($this->hasTableAndField('Product_OrderItem', 'ProductVersion')) {
289
            $table = 'Product_OrderItem';
290
        } elseif ($this->hasTableAndField('_obsolete_Product_OrderItem', 'ProductVersion')) {
291
            $table = '_obsolete_Product_OrderItem';
292
        }
293
        if ($this->hasTableAndField($table, 'ProductVersion')) {
294
            DB::query("
295
                UPDATE \"OrderItem\", \"$table\"
296
                    SET \"OrderItem\".\"Version\" = \"$table\".\"ProductVersion\"
297
                WHERE \"OrderItem\".\"ID\" = \"$table\".\"ID\"
298
            ");
299
            $this->makeFieldObsolete('Product_OrderItem', 'ProductVersion');
300
            $this->DBAlterationMessageNow('Migrating Product_OrderItem.ProductVersion to OrderItem.Version.', 'created');
301
        } else {
302
            $this->DBAlterationMessageNow('There is no need to migrate Product_OrderItem.ProductVersion to OrderItem.Version.');
303
        }
304
    }
305
306
    protected function productIDToBuyableID_26()
307
    {
308
        $explanation = '
309
            <h1>26. ProductID to to BuyableID</h1>
310
            <p>Move the product ID saved as Product_OrderItem.ProductID to OrderItem.BuyableID.</p>
311
        ';
312
        if ($this->retrieveInfoOnly) {
313
            return $explanation;
314
        } else {
315
            echo $explanation;
316
        }
317
        $table = 'LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL';
318
        if ($this->hasTableAndField('Product_OrderItem', 'ProductID')) {
319
            $table = 'Product_OrderItem';
320
        } elseif ($this->hasTableAndField('_obsolete_Product_OrderItem', 'ProductID')) {
321
            $table = '_obsolete_Product_OrderItem';
322
        }
323
        if ($this->hasTableAndField($table, 'ProductID')) {
324
            DB::query("
325
                UPDATE \"OrderItem\"
326
                    INNER JOIN \"$table\"
327
                        ON \"OrderItem\".\"ID\" = \"$table\".\"ID\"
328
                SET \"OrderItem\".\"BuyableID\" = \"$table\".\"ProductID\"
329
                WHERE \"BuyableID\" = 0 OR \"BuyableID\" IS NULL
330
            ");
331
            $this->makeFieldObsolete('Product_OrderItem', 'ProductID');
332
            $this->DBAlterationMessageNow('Migrating Product_OrderItem.ProductID to OrderItem.BuyableID', 'created');
333
        } else {
334
            $this->DBAlterationMessageNow('There is no need to migrate Product_OrderItem.ProductID to OrderItem.BuyableID');
335
        }
336
        if ($this->hasTableAndField($table, 'ProductVersion')) {
337
            DB::query("
338
                UPDATE \"OrderItem\"
339
                    INNER JOIN \"$table\"
340
                        ON \"OrderItem\".\"ID\" = \"$table\".\"ID\"
341
                SET \"OrderItem\".\"Version\" = \"$table\".\"ProductVersion\"
342
                WHERE \"BuyableID\" = 0 OR \"BuyableID\" IS NULL
343
            ");
344
            $this->makeFieldObsolete('Product_OrderItem', 'ProductID');
345
            $this->DBAlterationMessageNow('Migrating Product_OrderItem.ProductVersion to OrderItem.Version', 'created');
346
        } else {
347
            $this->DBAlterationMessageNow('There is no need to migrate Product_OrderItem.ProductVersion to OrderItem.Version');
348
        }
349
        // we must check for individual database types here because each deals with schema in a none standard way
350
        //can we use Table::has_field ???
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
351
        if ($this->hasTableAndField('ProductVariation_OrderItem', 'ProductVariationVersion')) {
352
            DB::query('
353
                UPDATE "OrderItem", "ProductVariation_OrderItem"
354
                    SET "OrderItem"."Version" = "ProductVariation_OrderItem"."ProductVariationVersion"
355
                WHERE "OrderItem"."ID" = "ProductVariation_OrderItem"."ID"
356
            ');
357
            $this->makeFieldObsolete('ProductVariation_OrderItem', 'ProductVariationVersion');
358
            $this->DBAlterationMessageNow('Migrating ProductVariation_OrderItem.ProductVariationVersion to OrderItem.Version', 'created');
359
        } else {
360
            $this->DBAlterationMessageNow('No need to migrate ProductVariation_OrderItem.ProductVariationVersion');
361
        }
362
        if (class_exists('ProductVariation_OrderItem')) {
363
            if ($this->hasTableAndField('ProductVariation_OrderItem', 'ProductVariationID')) {
364
                DB::query("
365
                    UPDATE \"OrderItem\", \"ProductVariation_OrderItem\"
366
                        SET \"OrderItem\".\"BuyableID\" = \"ProductVariation_OrderItem\".\"ProductVariationID\",
367
                                \"OrderItem\".\"BuyableClassName\" = 'ProductVariation'
368
                    WHERE \"OrderItem\".\"ID\" = \"ProductVariation_OrderItem\".\"ID\"
369
                ");
370
                $this->makeFieldObsolete('ProductVariation_OrderItem', 'ProductVariationID');
371
                $this->DBAlterationMessageNow('Migrating ProductVariation_OrderItem.ProductVariationID to OrderItem.BuyableID and adding BuyableClassName = ProductVariation', 'created');
372
            } else {
373
                $this->DBAlterationMessageNow('No need to migrate ProductVariation_OrderItem.ProductVariationID');
374
            }
375
        } else {
376
            $this->DBAlterationMessageNow('There are not ProductVariations in this project');
377
        }
378
    }
379
380
    protected function amountToCalculatedTotal_27()
381
    {
382
        $explanation = '
383
            <h1>27. Move OrderModifier.Amount to OrderAttribute.CalculatedTotal</h1>
384
            <p>Move the amount of the modifier in the OrderModifier.Amount field to the OrderAttribute.CalculatedTotal field.</p>
385
        ';
386
        if ($this->retrieveInfoOnly) {
387
            return $explanation;
388
        } else {
389
            echo $explanation;
390
        }
391
        if ($this->hasTableAndField('OrderModifier', 'Amount')) {
392
            DB::query('
393
                UPDATE "OrderModifier"
394
                    INNER JOIN "OrderAttribute"
395
                        ON "OrderAttribute"."ID" = "OrderModifier"."ID"
396
                SET "OrderAttribute"."CalculatedTotal" = "OrderModifier"."Amount"
397
                WHERE "OrderAttribute"."CalculatedTotal" IS NULL OR "OrderAttribute"."CalculatedTotal" = 0
398
            ');
399
            $this->makeFieldObsolete('OrderModifier', 'Amount');
400
            $this->DBAlterationMessageNow('Moved OrderModifier.Amount to OrderAttribute.CalculatedTotal', 'created');
401
        } else {
402
            $this->DBAlterationMessageNow('There is no need to move OrderModifier.Amount to OrderAttribute.CalculatedTotal');
403
        }
404
    }
405
406
    protected function currencyToMoneyFields_30()
407
    {
408
        $explanation = '
409
            <h1>30. Currency to Money Fields</h1>
410
            <p>Move the Payment Amount in the Amount field to a composite DB field (AmountAmount + AmountCurrency) </p>
411
        ';
412
        if ($this->retrieveInfoOnly) {
413
            return $explanation;
414
        } else {
415
            echo $explanation;
416
        }
417
        if ($this->hasTableAndField('Payment', 'Amount')) {
418
            //ECOMMERCE PAYMENT *************************
419
            DB::query('
420
                UPDATE "Payment"
421
                SET "AmountAmount" = "Amount"
422
                WHERE
423
                    "Amount" > 0
424
                    AND (
425
                        "AmountAmount" IS NULL OR "AmountAmount" = 0
426
                    )
427
            ');
428
            $countAmountChanges = DB::affectedRows();
0 ignored issues
show
Deprecated Code introduced by
The method DB::affectedRows() has been deprecated with message: since version 4.0 Use DB::affected_rows instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
429
            if ($countAmountChanges) {
430
                $this->DBAlterationMessageNow("Updated Payment.Amount field to 2.4 - $countAmountChanges rows updated", 'edited');
431
            }
432
        } else {
433
            $this->DBAlterationMessageNow('There is no need to move Payment.Amount to Payment.AmountAmount');
434
        }
435
        if ($this->hasTableAndField('Payment', 'Currency')) {
436
            DB::query("
437
                UPDATE \"Payment\"
438
                SET \"AmountCurrency\" = \"Currency\"
439
                WHERE
440
                    \"Currency\" <> ''
441
                    AND \"Currency\" IS NOT NULL
442
                    AND (
443
                        \"AmountCurrency\" IS NULL
444
                        OR \"AmountCurrency\" = ''
445
                    )
446
            ");
447
            $countCurrencyChanges = DB::affectedRows();
0 ignored issues
show
Deprecated Code introduced by
The method DB::affectedRows() has been deprecated with message: since version 4.0 Use DB::affected_rows instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
448
            if ($countCurrencyChanges) {
449
                $this->DBAlterationMessageNow("Updated Payment.Currency field to 2.4  - $countCurrencyChanges rows updated", 'edited');
450
            }
451
            if ($countAmountChanges != $countCurrencyChanges) {
0 ignored issues
show
Bug introduced by
The variable $countAmountChanges does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
452
                $this->DBAlterationMessageNow('Potential error in Payment fields update to 2.4, please review data', 'deleted');
453
            }
454
        } else {
455
            $this->DBAlterationMessageNow('There is no need to move Payment.Currency to Payment.AmountCurrency');
456
        }
457
    }
458
459
    protected function orderShippingCost_40()
460
    {
461
        $explanation = '
462
            <h1>40. Order Shipping Cost</h1>
463
            <p>Move the shipping cost in the order to its own modifier.</p>
464
        ';
465
        if ($this->retrieveInfoOnly) {
466
            return $explanation;
467
        } else {
468
            echo $explanation;
469
        }
470
        if ($this->hasTableAndField('Order', 'Shipping') && $this->hasTableAndField('Order', 'HasShippingCost')) {
471
            $orders = Order::get()
472
                ->where('"HasShippingCost" = 1 AND "Shipping" IS NOT NULL')
473
                ->limit($this->limit, $this->start);
474
            if ($orders->count()) {
475
                foreach ($orders as $order) {
476
                    $modifier1 = new SimpleShippingModifier();
477
                    $modifier1->CalculatedTotal = $shipping < 0 ? abs($shipping) : $shipping;
0 ignored issues
show
Bug introduced by
The variable $shipping does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
478
                    $modifier1->TableValue = $shipping < 0 ? abs($shipping) : $shipping;
479
                    $modifier1->OrderID = $id;
0 ignored issues
show
Bug introduced by
The variable $id does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
480
                    $modifier1->TableTitle = 'Delivery';
481
                    $modifier1->write();
482
                    $this->DBAlterationMessageNow(' ------------- Added shipping cost.', 'created');
483
                }
484
485
                return $this->start + $this->limit;
486
            } else {
487
                $this->DBAlterationMessageNow('There are no orders with HasShippingCost =1 and Shipping IS NOT NULL.');
488
            }
489
            $this->makeFieldObsolete('Order', 'HasShippingCost', 'tinyint(1)');
490
            $this->makeFieldObsolete('Order', 'Shipping', 'decimal(9,2)');
491
        } else {
492
            $this->DBAlterationMessageNow('No need to update shipping cost.');
493
        }
494
495
        return 0;
496
    }
497
498
    protected function orderTax_45()
499
    {
500
        $explanation = '
501
            <h1>45. Order Added Tax</h1>
502
            <p>Move the tax in the order to its own modifier.</p>
503
        ';
504
        if ($this->retrieveInfoOnly) {
505
            return $explanation;
506
        } else {
507
            echo $explanation;
508
        }
509
        if ($this->hasTableAndField('Order', 'AddedTax')) {
510
            $this->DBAlterationMessageNow('Moving Order.AddedTax to Modifier.', 'created');
511
            $orders = Order::get()
512
                ->where('"AddedTax" > 0')
513
                ->limit($this->limit, $this->start);
514
            if ($orders->count()) {
515
                foreach ($orders as $order) {
516
                    $id = $order->ID;
517
                    $hasShippingCost = DB::query("SELECT \"AddedTax\" FROM \"Order\" WHERE \"ID\" = '$id'")->value();
0 ignored issues
show
Unused Code introduced by
$hasShippingCost is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
518
                    $addedTax = DB::query("SELECT \"AddedTax\" FROM \"Order\" WHERE \"ID\" = '$id'")->value();
519
                    if ($addedTax != null && $addedTax > 0) {
520
                        $modifier1 = new FlatTaxModifier();
521
                        $modifier1->CalculatedTotal = $addedTax < 0 ? abs($addedTax) : $addedTax;
522
                        $modifier1->TableValue = $addedTax < 0 ? abs($addedTax) : $addedTax;
523
                        $modifier1->OrderID = $id;
524
                        $modifier1->TableTitle = 'Tax';
525
                        $modifier1->write();
526
                        $this->DBAlterationMessageNow(' ------------- Added tax.', 'created');
527
                    } else {
528
                        $this->DBAlterationMessageNow(' ------------- No need to add tax even though field is present');
529
                    }
530
                }
531
532
                return $this->start + $this->limit;
533
            } else {
534
                $this->DBAlterationMessageNow('There are no orders with a AddedTax field greater than zero.');
535
            }
536
            $this->makeFieldObsolete('Order', 'AddedTax');
537
        } else {
538
            $this->DBAlterationMessageNow('No need to update taxes.');
539
        }
540
541
        return 0;
542
    }
543
544
    protected function orderShippingAddress_50()
545
    {
546
        $explanation = '
547
            <h1>50. Order Shipping Address</h1>
548
            <p>Move a shipping address from within Order to its own class.</p>
549
        ';
550
        if ($this->retrieveInfoOnly) {
551
            return $explanation;
552
        } else {
553
            echo $explanation;
554
        }
555
        if ($this->hasTableAndField('Order', 'ShippingAddress')) {
556
            if ($this->hasTableAndField('Order', 'UseShippingAddress')) {
557
                $orders = Order::get()
558
                    ->where('"UseShippingAddress" = 1 AND "ShippingAddress"."ID" IS NULL')
559
                    ->leftJoin('ShippingAddress', '"Order"."ShippingAddressID" = "ShippingAddress"."ID"')
560
                    ->limit($this->limit, $this->start);
561
                if ($orders->count()) {
562
                    foreach ($orders as $order) {
563
                        if (!$order->ShippingAddressID) {
564
                            $obj = ShippingAddress::create();
565
                            if (isset($order->ShippingName)) {
566
                                $obj->ShippingName = $order->ShippingName;
0 ignored issues
show
Documentation introduced by
The property ShippingName does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
567
                            }
568
                            if (isset($order->ShippingAddress)) {
569
                                $obj->ShippingAddress = $order->ShippingAddress;
0 ignored issues
show
Documentation introduced by
The property ShippingAddress does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
570
                            }
571
                            if (isset($order->ShippingAddress2)) {
572
                                $obj->ShippingAddress2 = $order->ShippingAddress2;
0 ignored issues
show
Documentation introduced by
The property ShippingAddress2 does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
573
                            }
574
                            if (isset($order->ShippingCity)) {
575
                                $obj->ShippingCity = $order->ShippingCity;
0 ignored issues
show
Documentation introduced by
The property ShippingCity does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
576
                            }
577
                            if (isset($order->ShippingPostalCode)) {
578
                                $obj->ShippingPostalCode = $order->ShippingPostalCode;
0 ignored issues
show
Documentation introduced by
The property ShippingPostalCode does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
579
                            }
580
                            if (isset($order->ShippingState)) {
581
                                $obj->ShippingState = $order->ShippingState;
0 ignored issues
show
Documentation introduced by
The property ShippingState does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
582
                            }
583
                            if (isset($order->ShippingCountry)) {
584
                                $obj->ShippingCountry = $order->ShippingCountry;
0 ignored issues
show
Documentation introduced by
The property ShippingCountry does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
585
                            }
586
                            if (isset($order->ShippingPhone)) {
587
                                $obj->ShippingPhone = $order->ShippingPhone;
0 ignored issues
show
Documentation introduced by
The property ShippingPhone does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
588
                            }
589
                            if (isset($order->ShippingHomePhone)) {
590
                                $obj->ShippingPhone .= $order->ShippingHomePhone;
0 ignored issues
show
Documentation introduced by
The property ShippingPhone does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
591
                            }
592
                            if (isset($order->ShippingMobilePhone)) {
593
                                $obj->ShippingMobilePhone = $order->ShippingMobilePhone;
0 ignored issues
show
Documentation introduced by
The property ShippingMobilePhone does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
594
                            }
595
                            $obj->OrderID = $order->ID;
0 ignored issues
show
Documentation introduced by
The property OrderID does not exist on object<ShippingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
596
                            $obj->write();
597
                            $order->ShippingAddressID = $obj->ID;
598
                            $order->write();
599
                        } else {
600
                            $this->DBAlterationMessageNow('Strange contradiction occurred in Order with ID'.$order->ID, 'deleted');
601
                        }
602
                    }
603
604
                    return $this->start + $this->limit;
605
                } else {
606
                    $this->DBAlterationMessageNow('No orders need adjusting even though they followed the old pattern.');
607
                }
608
                $this->makeFieldObsolete('Order', 'ShippingName');
609
                $this->makeFieldObsolete('Order', 'ShippingAddress');
610
                $this->makeFieldObsolete('Order', 'ShippingAddress2');
611
                $this->makeFieldObsolete('Order', 'ShippingCity');
612
                $this->makeFieldObsolete('Order', 'ShippingPostalCode');
613
                $this->makeFieldObsolete('Order', 'ShippingState');
614
                $this->makeFieldObsolete('Order', 'ShippingCountry');
615
                $this->makeFieldObsolete('Order', 'ShippingPhone');
616
                $this->makeFieldObsolete('Order', 'ShippingHomePhone');
617
                $this->makeFieldObsolete('Order', 'ShippingMobilePhone');
618
            } else {
619
                $this->DBAlterationMessageNow('There is no UseShippingAddress field even though there is a ShippingAddress Field - this is an issue.', 'deleted');
620
            }
621
        } else {
622
            $this->DBAlterationMessageNow('Orders do not have the shipping address to migrate.');
623
        }
624
625
        return 0;
626
    }
627
628
    protected function orderBillingAddress_51()
629
    {
630
        $explanation = '
631
            <h1>51. Order Billing Address</h1>
632
            <p>Move the billing address from the order to its own class.</p>
633
        ';
634
        if ($this->retrieveInfoOnly) {
635
            return $explanation;
636
        } else {
637
            echo $explanation;
638
        }
639
        if ($this->hasTableAndField('Order', 'Address')) {
640
            if ($this->hasTableAndField('Order', 'City')) {
641
                $orders = Order::get()
642
                    ->where('"BillingAddress"."ID" = 0 OR "BillingAddress"."ID" IS NULL')
643
                    ->leftJoin('BillingAddress', '"Order"."BillingAddressID" = "BillingAddress"."ID"')
644
                    ->limit($this->limit, $this->start);
645
                if ($orders->count()) {
646
                    foreach ($orders as $order) {
647
                        if (!$order->BillingAddressID) {
648
                            $obj = BillingAddress::create();
649
                            if (isset($order->Email)) {
650
                                $obj->BillingEmail = $order->Email;
0 ignored issues
show
Documentation introduced by
The property BillingEmail does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
651
                            }
652
                            if (isset($order->Surname)) {
653
                                $obj->BillingSurname = $order->Surname;
0 ignored issues
show
Documentation introduced by
The property BillingSurname does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
654
                            }
655
                            if (isset($order->FirstName)) {
656
                                $obj->BillingFirstName = $order->FirstName;
0 ignored issues
show
Documentation introduced by
The property BillingFirstName does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
657
                            }
658
                            if (isset($order->Address)) {
659
                                $obj->BillingAddress = $order->Address;
0 ignored issues
show
Documentation introduced by
The property BillingAddress does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
660
                            }
661
                            if (isset($order->AddressLine2)) {
662
                                $obj->BillingAddress2 = $order->AddressLine2;
0 ignored issues
show
Documentation introduced by
The property BillingAddress2 does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
663
                            }
664
                            if (isset($order->Address2)) {
665
                                $obj->BillingAddress2 .= $order->Address2;
0 ignored issues
show
Documentation introduced by
The property BillingAddress2 does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
666
                            }
667
                            if (isset($order->City)) {
668
                                $obj->BillingCity = $order->City;
0 ignored issues
show
Documentation introduced by
The property BillingCity does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
669
                            }
670
                            if (isset($order->PostalCode)) {
671
                                $obj->BillingPostalCode = $order->PostalCode;
0 ignored issues
show
Documentation introduced by
The property BillingPostalCode does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
672
                            }
673
                            if (isset($order->State)) {
674
                                $obj->BillingState = $order->State;
0 ignored issues
show
Documentation introduced by
The property BillingState does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
675
                            }
676
                            if (isset($order->Country)) {
677
                                $obj->BillingCountry = $order->Country;
0 ignored issues
show
Documentation introduced by
The property BillingCountry does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
678
                            }
679
                            if (isset($order->Phone)) {
680
                                $obj->BillingPhone = $order->Phone;
0 ignored issues
show
Documentation introduced by
The property BillingPhone does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
681
                            }
682
                            if (isset($order->HomePhone)) {
683
                                $obj->BillingPhone .= $order->HomePhone;
0 ignored issues
show
Documentation introduced by
The property BillingPhone does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
684
                            }
685
                            if (isset($order->MobilePhone)) {
686
                                $obj->BillingMobilePhone = $order->MobilePhone;
0 ignored issues
show
Documentation introduced by
The property BillingMobilePhone does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
687
                            }
688
                            $obj->OrderID = $order->ID;
0 ignored issues
show
Documentation introduced by
The property OrderID does not exist on object<BillingAddress>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
689
                            $obj->write();
690
                            $order->BillingAddressID = $obj->ID;
691
                            $order->write();
692
                        } else {
693
                            $this->DBAlterationMessageNow('Strange contradiction occurred in Order with ID'.$order->ID, 'deleted');
694
                        }
695
                    }
696
697
                    return $this->start + $this->limit;
698
                } else {
699
                    $this->DBAlterationMessageNow('No orders need adjusting even though they followed the old pattern.');
700
                }
701
                $this->makeFieldObsolete('Order', 'Email');
702
                $this->makeFieldObsolete('Order', 'FirstName');
703
                $this->makeFieldObsolete('Order', 'Surname');
704
                $this->makeFieldObsolete('Order', 'Address');
705
                $this->makeFieldObsolete('Order', 'Address2');
706
                $this->makeFieldObsolete('Order', 'City');
707
                $this->makeFieldObsolete('Order', 'PostalCode');
708
                $this->makeFieldObsolete('Order', 'State');
709
                $this->makeFieldObsolete('Order', 'Country');
710
                $this->makeFieldObsolete('Order', 'Phone');
711
                $this->makeFieldObsolete('Order', 'HomePhone');
712
                $this->makeFieldObsolete('Order', 'MobilePhone');
713
            } else {
714
                $this->DBAlterationMessageNow('There is no UseBillingAddress field even though there is a BillingAddress Field - this is an issue.', 'deleted');
715
            }
716
        } else {
717
            $this->DBAlterationMessageNow('Orders do not have the Billing address to migrate.');
718
        }
719
720
        return 0;
721
    }
722
723
    protected function memberBillingAddress_52()
724
    {
725
        $explanation = '
726
            <h1>52. Member Billing Address</h1>
727
            <p>Move address details in the member table to its own class (billingaddress)</p>
728
        ';
729
        if ($this->retrieveInfoOnly) {
730
            return $explanation;
731
        } else {
732
            echo $explanation;
733
        }
734
        if ($this->hasTableAndField('Member', 'Address')) {
735
            if ($this->hasTableAndField('Member', 'City')) {
736
                $orders = Order::get()
737
                    ->where('"MemberID" > 0')
738
                    ->leftJoin('BillingAddress', '"Order"."BillingAddressID" = "BillingAddress"."ID"')
739
                    ->limit($this->limit, $this->start);
740
                if ($orders->count()) {
741
                    foreach ($orders as $order) {
742
                        $member = Member::get()->byID($order->MemberID);
743
                        if ($member) {
744
                            if ($obj = $order->BillingAddress()) {
745
                                $this->DBAlterationMessageNow('Order (id = '.$order->ID.') already has a billing address');
746
                            //do nothing
747
                            } else {
748
                                $this->DBAlterationMessageNow('Order (id = '.$order->ID.') now gets its own billing address...');
749
                                $obj = BillingAddress::create();
750
                            }
751
                            if (isset($member->Email) && !$obj->Email) {
752
                                $obj->Email = $member->Email;
753
                            }
754
                            if (isset($member->FirstName) && !$obj->FirstName) {
755
                                $obj->FirstName = $member->FirstName;
756
                            }
757
                            if (isset($member->Surname) && !$obj->Surname) {
758
                                $obj->Surname = $member->Surname;
759
                            }
760
                            if (isset($member->Address) && !$obj->Address) {
761
                                $obj->Address = $member->Address;
762
                            }
763
                            if (isset($member->AddressLine2) && !$obj->Address2) {
764
                                $obj->Address2 = $member->AddressLine2;
765
                            }
766
                            if (isset($member->City) && !$obj->City) {
767
                                $obj->City = $member->City;
768
                            }
769
                            if (isset($member->PostalCode) && !$obj->PostalCode) {
770
                                $obj->PostalCode = $member->PostalCode;
771
                            }
772
                            if (isset($member->State) && !$obj->State) {
773
                                $obj->State = $member->State;
774
                            }
775
                            if (isset($member->Country) && !$obj->Country) {
776
                                $obj->Country = $member->Country;
777
                            }
778
                            if (isset($member->Phone) && !$obj->Phone) {
779
                                $obj->Phone = $member->Phone;
780
                            }
781
                            if (isset($member->HomePhone) && !$obj->HomePhone) {
782
                                $obj->HomePhone .= $member->HomePhone;
783
                            }
784
                            if (isset($member->MobilePhone) && !$obj->MobilePhone) {
785
                                $obj->MobilePhone = $member->MobilePhone;
786
                            }
787
                            $obj->OrderID = $order->ID;
788
                            $obj->write();
789
                            $this->DBAlterationMessageNow('Updated Order #'.$order->ID.' with Member details', 'created');
790
                            DB::query('Update "Order" SET "BillingAddressID" = '.$obj->ID.' WHERE "Order".ID = '.$order->ID);
791
                        } else {
792
                            $this->DBAlterationMessageNow('There is no member associated with this order '.$order->ID, 'deleted');
793
                        }
794
                    }
795
796
                    return $this->start + $this->limit;
797
                } else {
798
                    $this->DBAlterationMessageNow('No orders need adjusting even though they followed the old pattern.');
799
                }
800
            } else {
801
                $this->DBAlterationMessageNow('There is no Address2 field, but there is an Address field in Member - this might be an issue.', 'deleted');
802
            }
803
        } else {
804
            $this->DBAlterationMessageNow('Members do not have a billing address to migrate.');
805
        }
806
807
        return 0;
808
    }
809
810
    protected function moveOrderStatus_60()
811
    {
812
        $explanation = '
813
            <h1>60. Move Order Status</h1>
814
            <p>Moving order status from the enum field to Order Step.</p>
815
        ';
816
        if ($this->retrieveInfoOnly) {
817
            return $explanation;
818
        } else {
819
            echo $explanation;
820
        }
821
        if ($this->hasTableAndField('Order', 'Status')) {
822
            // 2) Cancel status update
823
            $orders = Order::get()
824
                ->filter(array('Status' => 'Cancelled'))
825
                ->limit($this->limit, $this->start);
826
            if ($orders->count()) {
827
                foreach ($orders as $order) {
828
                    $order->CancelledByID = $admin->ID;
0 ignored issues
show
Bug introduced by
The variable $admin does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
829
                    $order->write();
830
                    $this->DBAlterationMessageNow('The order which status was \'Cancelled\' have been successfully changed to the status \'AdminCancelled\'', 'created');
831
                }
832
833
                return $this->start + $this->limit;
834
            } else {
835
                $this->DBAlterationMessageNow('There are no orders that are cancelled');
836
            }
837
            $rows = DB::query('SELECT "ID", "Status" FROM "Order"');
838
            if ($rows) {
839
                $cartObject = null;
840
                $unpaidObject = null;
841
                $paidObject = null;
842
                $sentObject = null;
0 ignored issues
show
Unused Code introduced by
$sentObject is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
843
                $adminCancelledObject = null;
844
                $memberCancelledObject = null;
845
                foreach ($rows as $row) {
846
                    switch ($row['Status']) {
847
                        case 'Cart':
848
                            if (!$cartObject) {
849
                                $cartObject = DataObject::get_one(
850
                                    'OrderStep',
851
                                    array('Code' => 'CREATED'),
852
                                    $cacheDataObjectGetOne = false
853
                                );
854
                                if ($cartObject) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
855
                                    //do nothing
856
                                } else {
857
                                    $this->DBAlterationMessageNow('Creating default steps', 'created');
858
                                    singleton('OrderStep')->requireDefaultRecords();
859
                                }
860
                            }
861
                            $cartObject = DataObject::get_one(
862
                                'OrderStep',
863
                                array('Code' => 'CREATED'),
864
                                $cacheDataObjectGetOne = false
865
                            );
866
                            if ($cartObject) {
867
                                DB::query('UPDATE "Order" SET "StatusID" = '.$cartObject->ID.' WHERE "Order"."ID" = '.$row['ID'].' AND ("StatusID" = 0 OR "StatusID" IS NULL)');
868
                            } else {
869
                                $this->DBAlterationMessageNow('Could not find CREATED status', 'deleted');
870
                            }
871
                            break;
872
                        case 'Query':
873
                        case 'Unpaid':
874
                            if (!$unpaidObject) {
875
                                $unpaidObject = DataObject::get_one(
876
                                    'OrderStep',
877
                                    array('Code' => 'SUBMITTED'),
878
                                    $cacheDataObjectGetOne = false
879
                                );
880
                                if ($unpaidObject) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
881
                                    //do nothing
882
                                } else {
883
                                    $this->DBAlterationMessageNow('Creating default steps', 'created');
884
                                    singleton('OrderStep')->requireDefaultRecords();
885
                                }
886
                            }
887
                            $unpaidObject = DataObject::get_one(
888
                                'OrderStep',
889
                                array('Code' => 'SUBMITTED'),
890
                                $cacheDataObjectGetOne = false
891
                            );
892
                            if ($unpaidObject) {
893
                                DB::query('UPDATE "Order" SET "StatusID" = '.$unpaidObject->ID.' WHERE "Order"."ID" = '.$row['ID'].' AND ("StatusID" = 0 OR "StatusID" IS NULL)');
894
                            } else {
895
                                $this->DBAlterationMessageNow('Could not find SUBMITTED status', 'deleted');
896
                            }
897
                            break;
898
                        case 'Processing':
899
                        case 'Paid':
900
                            if (!$paidObject) {
901
                                $paidObject = DataObject::get_one(
902
                                    'OrderStep',
903
                                    array('Code' => 'PAID'),
904
                                    $cacheDataObjectGetOne = false
905
                                );
906
                                if ($paidObject) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
907
                                    //do nothing
908
                                } else {
909
                                    $this->DBAlterationMessageNow('Creating default steps', 'created');
910
                                    singleton('OrderStep')->requireDefaultRecords();
911
                                }
912
                            }
913
                            $paidObject = DataObject::get_one(
914
                                'OrderStep',
915
                                array('Code' => 'PAID'),
916
                                $cacheDataObjectGetOne = false
917
                            );
918
                            if ($paidObject) {
919
                                DB::query('UPDATE "Order" SET "StatusID" = '.$paidObject->ID.' WHERE "Order"."ID" = '.$row['ID'].' AND ("StatusID" = 0 OR "StatusID" IS NULL)');
920
                                $this->DBAlterationMessageNow('Updating to PAID status', 'created');
921
                            } else {
922
                                $this->DBAlterationMessageNow('Could not find new status', 'deleted');
923
                            }
924
                            break;
925
                        case 'Sent':
926
                        case 'Complete':
927
                            //CHECK PAID VS SENT!
928
                            if (!$paidObject) {
929
                                $sentObject = DataObject::get_one(
930
                                    'OrderStep',
931
                                    array('Code' => 'SENT'),
932
                                    $cacheDataObjectGetOne = false
933
                                );
934
                                if ($sentObject) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
935
                                    //do nothing
936
                                } else {
937
                                    $this->DBAlterationMessageNow('Creating default steps', 'created');
938
                                    singleton('OrderStep')->requireDefaultRecords();
939
                                }
940
                            }
941
                            $sentObject = DataObject::get_one(
942
                                'OrderStep',
943
                                array('Code' => 'SENT'),
944
                                $cacheDataObjectGetOne = false
945
                            );
946
                            if ($sentObject) {
947
                                $this->DBAlterationMessageNow('Updating to SENT status', 'created');
948
                                DB::query('UPDATE "Order" SET "StatusID" = '.$sentObject->ID.' WHERE "Order"."ID" = '.$row['ID'].' AND ("StatusID" = 0 OR "StatusID" IS NULL)');
949
                            } elseif ($archivedObject = DataObject::get_one('OrderStep', array('Code' => 'ARCHIVED'), $cacheDataObjectGetOne = false)) {
950
                                $this->DBAlterationMessageNow('Updating to ARCHIVED status', 'created');
951
                                DB::query('UPDATE "Order" SET "StatusID" = '.$archivedObject->ID.' WHERE "Order"."ID" = '.$row['ID'].' AND ("StatusID" = 0 OR "StatusID" IS NULL)');
952
                            } else {
953
                                $this->DBAlterationMessageNow('Could not find new status', 'deleted');
954
                            }
955
                            break;
956
                        case 'AdminCancelled':
957
                            if (!$adminCancelledObject) {
958
                                $adminCancelledObject = DataObject::get_one(
959
                                    'OrderStep',
960
                                    array('Code' => 'SENT'),
961
                                    $cacheDataObjectGetOne = false
962
                                );
963
                                if ($adminCancelledObject) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
964
                                    //do nothing
965
                                } else {
966
                                    singleton('OrderStep')->requireDefaultRecords();
967
                                }
968
                            }
969
                            $adminID = Member::currentUserID();
970
                            if (!$adminID) {
971
                                $adminID = 1;
972
                            }
973
                            $this->DBAlterationMessageNow('Updating to Admin Cancelled', 'created');
974
                            DB::query('UPDATE "Order" SET "StatusID" = '.$adminCancelledObject->ID.', "CancelledByID" = '.$adminID.' WHERE "Order"."ID" = '.$row['ID'].' AND ("StatusID" = 0 OR "StatusID" IS NULL)');
975
                            break;
976
                        case 'MemberCancelled':
977
                            if (!$memberCancelledObject) {
978
                                $memberCancelledObject = DataObject::get_one(
979
                                    'OrderStep',
980
                                    array('Code' => 'SENT'),
981
                                    $cacheDataObjectGetOne = false
982
                                );
983
                                if ($memberCancelledObject) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
984
                                    //do nothing
985
                                } else {
986
                                    singleton('OrderStep')->requireDefaultRecords();
987
                                }
988
                            }
989
                            $this->DBAlterationMessageNow('Updating to MemberCancelled', 'created');
990
                            DB::query('UPDATE "Order" SET "StatusID" = '.$memberCancelledObject->ID.', "CancelledByID" = "MemberID" WHERE "Order"."ID" = '.$row['ID'].' AND ("StatusID" = 0 OR "StatusID" IS NULL)');
991
                            break;
992
                        default:
993
                            $this->DBAlterationMessageNow('Unexpected status', 'deleted');
994
                    }
995
                }
996
            } else {
997
                $this->DBAlterationMessageNow('No orders could be found.');
998
            }
999
            $this->makeFieldObsolete('Order', 'Status');
1000
        } else {
1001
            $this->DBAlterationMessageNow('There is no Status field in the Order Table.');
1002
        }
1003
1004
        return 0;
1005
    }
1006
1007
    protected function fixBadOrderStatus_68()
1008
    {
1009
        $explanation = '
1010
            <h1>68. Fix Bad Order Status</h1>
1011
            <p>Fixing any orders with an StatusID that is not in use...</p>
1012
        ';
1013
        if ($this->retrieveInfoOnly) {
1014
            return $explanation;
1015
        } else {
1016
            echo $explanation;
1017
        }
1018
        $firstOption = DataObject::get_one('OrderStep', null, $cacheDataObjectGetOne = false);
1019
        if ($firstOption) {
1020
            $badOrders = Order::get()
1021
                ->where('"StatusID" = 0 OR "StatusID" IS NULL OR "OrderStep"."ID" IS NULL')
1022
                ->leftJoin('OrderStep', '"Order"."StatusID" = "OrderStep"."ID"')
1023
                ->limit($this->limit, $this->start);
1024
            if ($badOrders->count()) {
1025
                foreach ($badOrders as $order) {
1026
                    if ($order->TotalItems() > 0) {
1027
                        DB::query('UPDATE "Order" SET "StatusID" = '.$firstOption->ID.' WHERE "Order"."ID" = '.$order->ID);
1028
                        $this->DBAlterationMessageNow('No order status for order number #'.$order->ID." reverting to: $firstOption->Name.", 'error');
1029
                    }
1030
                }
1031
1032
                return $this->start + $this->limit;
1033
            } else {
1034
                $this->DBAlterationMessageNow('There are no orders with incorrect order status.');
1035
            }
1036
        } else {
1037
            $this->DBAlterationMessageNow('No first order step.', 'error');
1038
        }
1039
1040
        return 0;
1041
    }
1042
1043
    protected function updateProductGroups_110()
1044
    {
1045
        $explanation = "
1046
            <h1>110. Update Product Groups: </h1>
1047
            <p>Set the product groups 'show products' to the default.</p>
1048
        ";
1049
        if ($this->retrieveInfoOnly) {
1050
            return $explanation;
1051
        } else {
1052
            echo $explanation;
1053
        }
1054
        $checkIfAnyLevelsAreSetAtAll = DB::query('SELECT COUNT(ID) FROM "ProductGroup" WHERE "LevelOfProductsToShow" <> 0 AND "LevelOfProductsToShow" IS NOT NULL')->value();
1055
        $productGroupDefaults = Config::inst()->get('ProductGroup', 'defaults');
1056
        if ($checkIfAnyLevelsAreSetAtAll == 0 && $productGroupDefaults['LevelOfProductsToShow'] != 0) {
1057
            //level of products to show
1058
            DB::query(
1059
                '
1060
                UPDATE "ProductGroup"
1061
                SET "LevelOfProductsToShow" = '.$productGroupDefaults['LevelOfProductsToShow'].'
1062
                WHERE "LevelOfProductsToShow" = 0 OR "LevelOfProductsToShow" IS NULL '
1063
            );
1064
            DB::query(
1065
                '
1066
                UPDATE "ProductGroup_Live"
1067
                SET "LevelOfProductsToShow" = '.$productGroupDefaults['LevelOfProductsToShow'].'
1068
                WHERE "LevelOfProductsToShow" = 0 OR "LevelOfProductsToShow"  IS NULL '
1069
            );
1070
            $this->DBAlterationMessageNow("resetting product 'show' levels", 'created');
1071
            //default sort order
1072
            DB::query(
1073
                '
1074
                UPDATE "ProductGroup"
1075
                SET "DefaultSortOrder" = '.$productGroupDefaults['DefaultSortOrder']."
1076
                WHERE \"DefaultSortOrder\" = 0 OR  \"DefaultSortOrder\" = '' OR  \"DefaultSortOrder\" IS NULL "
1077
            );
1078
            DB::query(
1079
                '
1080
                UPDATE "ProductGroup_Live"
1081
                SET "DefaultSortOrder" = '.$productGroupDefaults['DefaultSortOrder']."
1082
                WHERE \"DefaultSortOrder\" = 0 OR  \"DefaultSortOrder\" = '' OR  \"DefaultSortOrder\" IS NULL "
1083
            );
1084
            $this->DBAlterationMessageNow('resetting product default sort order', 'created');
1085
            //default filter
1086
            DB::query(
1087
                '
1088
                UPDATE "ProductGroup"
1089
                SET "DefaultFilter" = '.$productGroupDefaults['DefaultFilter']."
1090
                WHERE \"DefaultFilter\" = 0 OR  \"DefaultFilter\" = '' OR  \"DefaultFilter\" IS NULL "
1091
            );
1092
            DB::query(
1093
                '
1094
                UPDATE "ProductGroup_Live"
1095
                SET "DefaultFilter" = '.$productGroupDefaults['DefaultFilter']."
1096
                WHERE \"DefaultFilter\" = 0 OR  \"DefaultFilter\" = '' OR  \"DefaultFilter\" IS NULL "
1097
            );
1098
            $this->DBAlterationMessageNow('resetting product default filter', 'created');
1099
        } else {
1100
            $this->DBAlterationMessageNow("there is no need for resetting product 'show' levels");
1101
        }
1102
1103
        return 0;
1104
    }
1105
1106
    protected function setFixedPriceForSubmittedOrderItems_120()
1107
    {
1108
        $explanation = '
1109
            <h1>120. Set Fixed Price for Submitted Order Items: </h1>
1110
            <p>Migration task to fix the price for submitted order items.</p>
1111
        ';
1112
        if ($this->retrieveInfoOnly) {
1113
            return $explanation;
1114
        } else {
1115
            echo $explanation;
1116
        }
1117
        if ($this->hasTableAndField('OrderModifier', 'CalculationValue')) {
1118
            DB::query(
1119
                '
1120
                UPDATE "OrderAttribute"
1121
                INNER JOIN "OrderModifier"
1122
                    ON "OrderAttribute"."ID" = "OrderModifier"."ID"
1123
                SET "OrderAttribute"."CalculatedTotal" = "OrderModifier"."CalculationValue"
1124
                WHERE "OrderAttribute"."CalculatedTotal" = 0'
1125
            );
1126
            $this->makeFieldObsolete('OrderModifier', 'CalculationValue');
1127
            $this->DBAlterationMessageNow('Moving values from OrderModifier.CalculationValue to OrderAttribute.CalculatedTotal', 'created');
1128
        } else {
1129
            $this->DBAlterationMessageNow('There is no need to move values from OrderModifier.CalculationValue to OrderAttribute.CalculatedTotal');
1130
        }
1131
        /////////////////////////////////
1132
        ///////// We should not include the code below
1133
        ///////// Because it may affect past orders badly.
1134
        /////////////////////////////////
1135
        /////////////////////////////////
1136
        return;
1137
        $orderItems = Order::get()
0 ignored issues
show
Unused Code introduced by
$orderItems = \Order::ge...->limit, $this->start); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1138
            ->where('"Quantity" <> 0 AND "OrderAttribute"."CalculatedTotal" = 0')
1139
            ->sort('"Created" ASC')
1140
            ->limit($this->limit, $this->start);
1141
        $count = 0;
1142
        if ($orderItems->count()) {
1143
            foreach ($orderItems as $orderItem) {
1144
                if ($orderItem->Order()) {
1145
                    if ($orderItem->Order()->IsSubmitted()) {
1146
                        //TO DO: WHAT THE HELL IS THAT (true)
1147
                        $unitPrice = $orderItem->UnitPrice($recalculate = true);
1148
                        if ($unitPrice) {
1149
                            $orderItem->CalculatedTotal = $unitPrice * $orderItem->Quantity;
1150
                            $orderItem->write();
1151
                            ++$count;
1152
                            $this->DBAlterationMessageNow('RECALCULATING: '.$orderItem->UnitPrice($recalculate = true).' * '.$orderItem->Quantity.' = '.$orderItem->CalculatedTotal.' for OrderItem #'.$orderItem->ID, 'created');
1153
                        }
1154
                    } else {
1155
                        $this->DBAlterationMessageNow('OrderItem is part of not-submitted order.');
1156
                    }
1157
                } else {
1158
                    $this->DBAlterationMessageNow('OrderItem does not have an order! (OrderItemID: '.$orderItem->ID.')', 'deleted');
1159
                }
1160
            }
1161
        } else {
1162
            $this->DBAlterationMessageNow('All order items have a calculated total....');
1163
        }
1164
        if ($count) {
1165
            $this->DBAlterationMessageNow("Fixed price for all submmitted orders without a fixed one - affected: $count order items", 'created');
1166
        }
1167
1168
        return 0;
1169
    }
1170
1171
    protected function moveSiteConfigToEcommerceDBConfig_140()
1172
    {
1173
        $explanation = '
1174
            <h1>140. Move Site Config fields to Ecommerce DB Config</h1>
1175
            <p>Moving the general config fields from the SiteConfig to the EcommerceDBConfig.</p>
1176
        ';
1177
        if ($this->retrieveInfoOnly) {
1178
            return $explanation;
1179
        } else {
1180
            echo $explanation;
1181
        }
1182
        $fields = array(
1183
            'ShopClosed',
1184
            'ShopPricesAreTaxExclusive',
1185
            'ShopPhysicalAddress',
1186
            'ReceiptEmail',
1187
            'PostalCodeURL',
1188
            'PostalCodeLabel',
1189
            'NumberOfProductsPerPage',
1190
            'OnlyShowProductsThatCanBePurchased',
1191
            'ProductsHaveWeight',
1192
            'ProductsHaveModelNames',
1193
            'ProductsHaveQuantifiers',
1194
            'ProductsAlsoInOtherGroups',
1195
            //"ProductsHaveVariations",
1196
            'EmailLogoID',
1197
            'DefaultProductImageID',
1198
        );
1199
        $ecomConfig = DataObject::get_one('EcommerceDBConfig', null, $cacheDataObjectGetOne = false);
1200
        if (!$ecomConfig) {
1201
            $ecomConfig = EcommerceDBConfig::create();
1202
            $ecomConfig->write();
1203
        }
1204
        $sc = SiteConfig::current_site_config();
1205
        if ($ecomConfig && $sc) {
1206
            foreach ($fields as $field) {
1207
                if ($this->hasTableAndField('SiteConfig', $field)) {
1208
                    if (!$this->hasTableAndField('EcommerceDBConfig', $field)) {
1209
                        $this->DBAlterationMessageNow("Could not find EcommerceDBConfig.$field - this is unexpected!", 'deleted');
1210
                    } else {
1211
                        $this->DBAlterationMessageNow("Migrated SiteConfig.$field", 'created');
1212
                        $ecomConfig->$field = DB::query("SELECT \"$field\" FROM \"SiteConfig\" WHERE \"ID\" = ".$sc->ID)->value();
1213
                        $ecomConfig->write();
1214
                        $this->makeFieldObsolete('SiteConfig', $field);
1215
                    }
1216
                } else {
1217
                    $this->DBAlterationMessageNow("SiteConfig.$field has been moved");
1218
                }
1219
            }
1220
        } else {
1221
            $this->DBAlterationMessageNow('ERROR: SiteConfig or EcommerceDBConfig are not available', 'deleted');
1222
        }
1223
1224
        return 0;
1225
    }
1226
1227
    public function addClassNameToOrderItems_150()
1228
    {
1229
        $explanation = '
1230
            <h1>150. Add a class name to all buyables.</h1>
1231
            <p>ClassNames used to be implied, this is now saved as OrderItem.BuyableClassName.</p>
1232
        ';
1233
        if ($this->retrieveInfoOnly) {
1234
            return $explanation;
1235
        } else {
1236
            echo $explanation;
1237
        }
1238
        $rows = DB::query("
1239
            SELECT \"OrderAttribute\".\"ID\", \"ClassName\"
1240
            FROM \"OrderAttribute\"
1241
                INNER JOIN \"OrderItem\" ON \"OrderItem\".\"ID\" = \"OrderAttribute\".\"ID\"
1242
            WHERE \"BuyableClassName\" = '' OR \"BuyableClassName\" IS NULL;
1243
        ");
1244
        if ($rows) {
1245
            foreach ($rows as $row) {
1246
                $orderItemPostFix = '_OrderItem';
1247
                $id = $row['ID'];
1248
                $className = str_replace($orderItemPostFix, '', $row['ClassName']);
1249
                if (class_exists($className) && ClassInfo::is_subclass_of($className, 'DataObject')) {
0 ignored issues
show
Bug introduced by
The method is_subclass_of() does not seem to exist on object<ClassInfo>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1250
                    DB::query("
1251
                        UPDATE \"OrderItem\"
1252
                        SET \"BuyableClassName\" = '$className'
1253
                        WHERE \"ID\" = $id;
1254
                    ");
1255
                    $this->DBAlterationMessageNow("Updating Order.BuyableClassName ( ID = $id ) to $className.", 'created');
1256
                } else {
1257
                    $this->DBAlterationMessageNow("Order Item with ID = $id does not have a valid class name. This needs investigation.", 'deleted');
1258
                }
1259
            }
1260
        } else {
1261
            $this->DBAlterationMessageNow('No order items could be found that need updating.');
1262
        }
1263
1264
        return 0;
1265
    }
1266
1267
    public function addTermsAndConditionsMessage_160()
1268
    {
1269
        $explanation = '
1270
            <h1>160. Add checkout message TermsAndConditionsMessage message.</h1>
1271
            <p>Adds TermsAndConditionsMessage if there is a terms page.</p>
1272
        ';
1273
        if ($this->retrieveInfoOnly) {
1274
            return $explanation;
1275
        } else {
1276
            echo $explanation;
1277
        }
1278
        $checkoutPage = DataObject::get_one('CheckoutPage', null, $cacheDataObjectGetOne = false);
1279
        if ($checkoutPage) {
1280
            if ($checkoutPage->TermsPageID) {
1281
                if (!$checkoutPage->TermsAndConditionsMessage) {
1282
                    $checkoutPageDefaults = Config::inst()->get('CheckoutPage', 'defaults');
1283
                    $checkoutPage->TermsAndConditionsMessage = $checkoutPageDefaults['TermsAndConditionsMessage'];
1284
                    $checkoutPage->writeToStage('Stage');
1285
                    $checkoutPage->publish('Stage', 'Live');
1286
                    $this->DBAlterationMessageNow('Added TermsAndConditionsMessage', 'created');
1287
                } else {
1288
                    $this->DBAlterationMessageNow('There was no need to add a terms and conditions message because there was already a message.');
1289
                }
1290
            } else {
1291
                $this->DBAlterationMessageNow('There was no need to add a terms and conditions message because there is no terms and conditions page.');
1292
            }
1293
        } else {
1294
            $this->DBAlterationMessageNow('There was no need to add a terms and conditions message because there is no checkout page', 'deleted');
1295
        }
1296
1297
        return 0;
1298
    }
1299
1300
    public function mergeUncompletedOrderForOneMember_170()
1301
    {
1302
        $explanation = '
1303
            <h1>170. Merge uncompleted orders into one.</h1>
1304
            <p>Merges uncompleted orders by the same user into one.</p>
1305
        ';
1306
        if ($this->retrieveInfoOnly) {
1307
            return $explanation;
1308
        } else {
1309
            echo $explanation;
1310
        }
1311
        $orders = Order::get()
1312
            ->filter(array('MemberID:GreaterThan' => 0))
1313
            ->sort(array(
1314
                'MemberID' => 'ASC',
1315
                '"Order"."Created"' => 'DESC',
1316
            ))
1317
            ->innerJoin('Member', '"Order"."MemberID" = "Member"."ID"')
1318
            ->limit($this->limit, $this->start);
1319
        $count = 0;
1320
        $previousOrderMemberID = 0;
1321
        $lastOrderFromMember = null;
1322
        if ($orders->count()) {
1323
            foreach ($orders as $order) {
1324
                //crucial ONLY for non-submitted orders...
1325
                if ($order->IsSubmitted()) {
1326
                    //do nothing!
1327
                    ++$count;
1328
                } else {
1329
                    $memberID = $order->MemberID;
1330
                    //recurring member
1331
                    if ($previousOrderMemberID == $memberID && $lastOrderFromMember) {
1332
                        $this->DBAlterationMessageNow('We have a duplicate order for a member: '.$order->Member()->Email, 'created');
1333
                        $orderAttributes = OrderAttribute::get()
1334
                            ->filter(array('OrderID' => $order->ID));
1335
                        if ($orderAttributes->count()) {
1336
                            foreach ($orderAttributes as $orderAttribute) {
1337
                                $this->DBAlterationMessageNow('Moving attribute #'.$orderAttribute->ID, 'created');
1338
                                DB::query('UPDATE "OrderAttribute" SET "OrderID" = '.$lastOrderFromMember->ID.' WHERE "ID" = '.$orderAttribute->ID);
1339
                            }
1340
                        } else {
1341
                            $this->DBAlterationMessageNow('There are no attributes for this order');
1342
                        }
1343
                        $orderStatusLogs = OrderStatusLog::get()->filter(array('OrderID' => $order->ID));
1344
                        if ($orderStatusLogs->count()) {
1345
                            foreach ($orderStatusLogs as $orderStatusLog) {
1346
                                $this->DBAlterationMessageNow('Moving order status log #'.$orderStatusLog->ID, 'created');
1347
                                DB::query('UPDATE "OrderStatusLog" SET "OrderID" = '.$lastOrderFromMember->ID.' WHERE "ID" = '.$orderStatusLog->ID);
1348
                            }
1349
                        } else {
1350
                            $this->DBAlterationMessageNow('There are no order status logs for this order');
1351
                        }
1352
                        $orderEmailRecords = OrderEmailRecord::get()->filter(array('OrderID' => $order->ID));
1353
                        if ($orderEmailRecords->count()) {
1354
                            foreach ($orderEmailRecords as $orderEmailRecord) {
1355
                                DB::query('UPDATE "OrderEmailRecord" SET "OrderID" = '.$lastOrderFromMember->ID.' WHERE "ID" = '.$orderEmailRecord->ID);
1356
                                $this->DBAlterationMessageNow('Moving email #'.$orderEmailRecord->ID, 'created');
1357
                            }
1358
                        } else {
1359
                            $this->DBAlterationMessageNow('There are no emails for this order.');
1360
                        }
1361
                    }
1362
                    //new member
1363
                    else {
1364
                        $previousOrderMemberID = $order->MemberID;
1365
                        $lastOrderFromMember = $order;
1366
                        $this->DBAlterationMessageNow('Found last order from member.');
1367
                    }
1368
                    if ($order->BillingAddressID && !$lastOrderFromMember->BillingAddressID) {
1369
                        $this->DBAlterationMessageNow('Moving Billing Address.');
1370
                        DB::query('UPDATE "Order" SET "BillingAddressID" = '.$order->BillingAddressID.' WHERE "ID" = '.$lastOrderFromMember->ID);
1371
                        DB::query('UPDATE "BillingAddress" SET "OrderID" = '.$lastOrderFromMember->ID.' WHERE "ID" = '.$order->BillingAddressID);
1372
                    }
1373
                    if ($order->ShippingAddressID && !$lastOrderFromMember->ShippingAddressID) {
1374
                        $this->DBAlterationMessageNow('Moving Shipping Address.');
1375
                        DB::query('UPDATE "Order" SET "ShippingAddressID" = '.$order->ShippingAddressID.' WHERE "ID" = '.$lastOrderFromMember->ID);
1376
                        DB::query('UPDATE "ShippingAddress" SET "OrderID" = '.$lastOrderFromMember->ID.' WHERE "ID" = '.$order->ShippingAddressID);
1377
                    }
1378
                    $order->delete();
1379
                }
1380
            }
1381
            $this->DBAlterationMessageNow("Ignored $count Orders that have already been submitted.");
1382
1383
            return $this->start + $this->limit;
1384
        } else {
1385
            $this->DBAlterationMessageNow('There were no orders at all to work through.');
1386
        }
1387
1388
        return 0;
1389
    }
1390
1391
    public function updateFullSiteTreeSortFieldForAllProducts_180()
1392
    {
1393
        $explanation = '
1394
            <h1>180. Set starting value Product.FullSiteTreeSort Field.</h1>
1395
            <p>Sets a starting value for a new field: FullSiteTreeSortField.</p>
1396
        ';
1397
        if ($this->retrieveInfoOnly) {
1398
            return $explanation;
1399
        } else {
1400
            echo $explanation;
1401
        }
1402
        //level 10
1403
        $task = new EcommerceTaskCleanupProducts();
1404
        $task->setDeleteFirst(false);
1405
        $task->run(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<SS_HTTPRequest>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1406
1407
        return 0;
1408
    }
1409
1410
    public function updateOrderStatusLogSequentialOrderNumber_190()
1411
    {
1412
        $explanation = '
1413
            <h1>190. Set sequential order numbers</h1>
1414
            <p>Prepopulates old orders for OrderStatusLog_Submitted.SequentialOrderNumber.</p>
1415
        ';
1416
        if ($this->retrieveInfoOnly) {
1417
            return $explanation;
1418
        } else {
1419
            echo $explanation;
1420
        }
1421
        $submittedOrdersLog = OrderStatusLog_Submitted::get()
1422
            ->sort('Created', 'ASC')
1423
            ->limit($this->limit, $this->start);
1424
        $changes = 0;
1425
        if ($submittedOrdersLog->count()) {
1426
            foreach ($submittedOrdersLog as $submittedOrderLog) {
1427
                $old = $submittedOrderLog->SequentialOrderNumber;
1428
                $submittedOrderLog->write();
1429
                $new = $submittedOrderLog->SequentialOrderNumber;
1430
                if ($old != $new) {
1431
                    ++$changes;
1432
                    $this->DBAlterationMessageNow('Changed the SequentialOrderNumber for order #'.$submittedOrderLog->OrderID." from $old to $new ");
1433
                }
1434
            }
1435
            if (!$changes) {
1436
                $this->DBAlterationMessageNow('There were no changes in any of the OrderStatusLog_Submitted.SequentialOrderNumber fields.');
1437
            }
1438
1439
            return $this->start + $this->limit;
1440
        } else {
1441
            $this->DBAlterationMessageNow('There are no logs to update.');
1442
        }
1443
1444
        return 0;
1445
    }
1446
1447
    public function resaveAllPRoducts_200()
1448
    {
1449
        $explanation = '
1450
            <h1>200. Resave All Products to update the FullName and FullSiteTreeSort Field</h1>
1451
            <p>Saves and PUBLISHES all the products on the site. You may need to run this task several times.</p>
1452
        ';
1453
        if ($this->retrieveInfoOnly) {
1454
            return $explanation;
1455
        } else {
1456
            echo $explanation;
1457
        }
1458
        $count = 0;
1459
        $products = Product::get()
1460
            ->where("\"FullName\" = '' OR \"FullName\" IS NULL")
1461
            ->sort('ID', 'ASC')
1462
            ->limit($this->limit, $this->start);
1463
        if ($products->count()) {
1464
            foreach ($products as $product) {
1465
                ++$count;
1466
                $product->writeToStage('Stage');
1467
                $product->publish('Stage', 'Live');
1468
                $this->DBAlterationMessageNow('Saving Product '.$product->Title);
1469
            }
1470
1471
            return $this->start + $this->limit;
1472
        } else {
1473
            $this->DBAlterationMessageNow('No products to update.');
1474
        }
1475
1476
        return 0;
1477
    }
1478
1479
    public function resaveAllPRoductsVariations_210()
1480
    {
1481
        $explanation = '
1482
            <h1>210. Resave All Product Variations to update the FullName and FullSiteTreeSort Field</h1>
1483
            <p>Saves all the product variations on the site. You may need to run this task several times.</p>
1484
        ';
1485
        if ($this->retrieveInfoOnly) {
1486
            return $explanation;
1487
        } else {
1488
            echo $explanation;
1489
        }
1490
        $count = 0;
1491
        if (class_exists('ProductVariation')) {
1492
            ProductVariation::get()
1493
                ->where("\"FullName\" = '' OR \"FullName\" IS NULL")
1494
                ->sort('ID', 'ASC')
1495
                ->limit($this->limit, $this->start);
1496
            if ($variations->count()) {
1497
                foreach ($variations as $variation) {
0 ignored issues
show
Bug introduced by
The variable $variations does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1498
                    ++$count;
1499
                    $variation->write();
1500
                    $this->DBAlterationMessageNow('Saving Variation '.$variation->getTitle());
1501
                }
1502
1503
                return $this->start + $this->limit;
1504
            } else {
1505
                $this->DBAlterationMessageNow('No product variations to update.');
1506
            }
1507
        } else {
1508
            $this->DBAlterationMessageNow('There are not ProductVariations in this project');
1509
        }
1510
1511
        return 0;
1512
    }
1513
1514
    public function addConfirmationPage_250()
1515
    {
1516
        $explanation = '
1517
            <h1>250. Add Confirmation Page</h1>
1518
            <p>Creates a checkout page and order confirmation page in case they do not exist.</p>
1519
        ';
1520
        if ($this->retrieveInfoOnly) {
1521
            return $explanation;
1522
        } else {
1523
            echo $explanation;
1524
        }
1525
        $checkoutPage = DataObject::get_one('CheckoutPage', null, $cacheDataObjectGetOne = false);
1526
        if (!$checkoutPage) {
1527
            $checkoutPage = new CheckoutPage();
1528
            $this->DBAlterationMessageNow('Creating a CheckoutPage', 'created');
1529
        } else {
1530
            $this->DBAlterationMessageNow('No need to create a CheckoutPage Page');
1531
        }
1532
        if ($checkoutPage) {
1533
            $checkoutPage->HasCheckoutSteps = 1;
1534
            $checkoutPage->writeToStage('Stage');
1535
            $checkoutPage->publish('Stage', 'Live');
1536
            $orderConfirmationPage = DataObject::get_one('OrderConfirmationPage', null, $cacheDataObjectGetOne = false);
1537
            if ($orderConfirmationPage) {
1538
                $this->DBAlterationMessageNow('No need to create an Order Confirmation Page');
1539
            } else {
1540
                $orderConfirmationPage = new OrderConfirmationPage();
1541
                $orderConfirmationPage->ParentID = $checkoutPage->ID;
1542
                $orderConfirmationPage->writeToStage('Stage');
1543
                $orderConfirmationPage->publish('Stage', 'Live');
1544
                $this->DBAlterationMessageNow('Creating an Order Confirmation Page', 'created');
1545
            }
1546
        } else {
1547
            $this->DBAlterationMessageNow('There is no CheckoutPage available', 'deleted');
1548
        }
1549
1550
        return 0;
1551
    }
1552
1553
    public function cleanupImages_260()
1554
    {
1555
        $explanation = '
1556
            <h1>260. Cleanup Images</h1>
1557
            <p>Checks the class name of all product images and makes sure they exist.</p>
1558
        ';
1559
        if ($this->retrieveInfoOnly) {
1560
            return $explanation;
1561
        } else {
1562
            echo $explanation;
1563
        }
1564
        $task = new EcommerceTaskProductImageReset();
1565
        $task->run(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<SS_HTTPRequest>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1566
1567
        return 0;
1568
    }
1569
1570
    public function addNewPopUpManager_280()
1571
    {
1572
        $explanation = '
1573
            <h1>280. Add new pop-up manager</h1>
1574
            <p>Replaces a link to a JS Library in the config file</p>
1575
        ';
1576
        if ($this->retrieveInfoOnly) {
1577
            return $explanation;
1578
        } else {
1579
            echo $explanation;
1580
        }
1581
        $oldJSLibrary = 'ecommerce/thirdparty/simpledialogue_fixed/jquery.simpledialog.0.1.js';
1582
        $newJSLibrary = 'ecommerce/thirdparty/colorbox/jquery.colorbox-min.js';
1583
        $fileArray = Config::inst()->get('EcommerceConfig', 'folder_and_file_locations');
1584
        if ($fileArray && count($fileArray)) {
1585
            foreach ($fileArray as $folderAndFileLocationWithoutBase) {
0 ignored issues
show
Bug introduced by
The expression $fileArray of type array|integer|double|string|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1586
                if ($folderAndFileLocationWithoutBase != 'ecommerce/_config/ecommerce.yml') {
1587
                    $folderAndFileLocationWithBase = Director::baseFolder().'/'.$folderAndFileLocationWithoutBase;
1588
                    if (file_exists($folderAndFileLocationWithBase)) {
1589
                        $fp = @fopen($folderAndFileLocationWithBase, 'r');
1590
                        if ($fp) {
1591
                            $oldContent = fread($fp, filesize($folderAndFileLocationWithBase));
1592
                            $newContent = str_replace($oldJSLibrary, $newJSLibrary, $oldContent);
1593
                            if ($oldContent != $newContent) {
1594
                                fclose($fp);
1595
                                $fp = fopen($folderAndFileLocationWithBase, 'w+');
1596
                                if (fwrite($fp, $newContent)) {
1597
                                    $this->DBAlterationMessageNow("file updated from $oldJSLibrary to $newJSLibrary in  $folderAndFileLocationWithoutBase", 'created');
1598
                                } else {
1599
                                    $this->DBAlterationMessageNow("Could NOT update from $oldJSLibrary to $newJSLibrary in  $folderAndFileLocationWithoutBase");
1600
                                }
1601
                                fclose($fp);
1602
                            } else {
1603
                                $this->DBAlterationMessageNow("There is no need to update $folderAndFileLocationWithBase");
1604
                            }
1605
                        } else {
1606
                            $this->DBAlterationMessageNow("it seems that $folderAndFileLocationWithBase - does not have the right permission, please change manually.", 'deleted');
1607
                        }
1608
                    } else {
1609
                        $this->DBAlterationMessageNow("Could not find $folderAndFileLocationWithBase - even though it is referenced in EcommerceConfig::\$folder_and_file_locations", 'deleted');
1610
                    }
1611
                } else {
1612
                    $this->DBAlterationMessageNow('There is no need to replace the ecommerce default file: ecommerce/_config/ecommerce.yml', 'created');
1613
                }
1614
            }
1615
        } else {
1616
            $this->DBAlterationMessageNow('Could not find any config files (most usual place: mysite/_config/ecommerce.yml)', 'deleted');
1617
        }
1618
1619
        return 0;
1620
    }
1621
1622
    public function addCurrencyCodeIDToOrders_290()
1623
    {
1624
        $explanation = '
1625
            <h1>290. Add Curenccy to Orders</h1>
1626
            <p>Sets all currencies to the default currency for all orders without a currency.</p>
1627
        ';
1628
        if ($this->retrieveInfoOnly) {
1629
            return $explanation;
1630
        } else {
1631
            echo $explanation;
1632
        }
1633
        $ordersWithoutCurrencyCount = Order::get()->filter(array('CurrencyUsedID' => 0))->count();
1634
        if ($ordersWithoutCurrencyCount) {
1635
            $currencyID = EcommerceCurrency::default_currency_id();
1636
            DB::query("UPDATE \"Order\" SET \"CurrencyUsedID\" = $currencyID WHERE \"CurrencyUsedID\" = 0");
1637
            $this->DBAlterationMessageNow("All orders ($ordersWithoutCurrencyCount) have been set a currency value.", 'changed');
1638
        }
1639
1640
        return 0;
1641
    }
1642
1643
    public function MovePaymentToEcommercePayment_300()
1644
    {
1645
        $explanation = '
1646
            <h1>300. Migrating Payment to EcommercePayment</h1>
1647
            <p>We move the data from Payment to EcommercePayment.</p>
1648
        ';
1649
        if ($this->retrieveInfoOnly) {
1650
            return $explanation;
1651
        } else {
1652
            echo $explanation;
1653
        }
1654
        $db = DB::getConn();
0 ignored issues
show
Deprecated Code introduced by
The method DB::getConn() has been deprecated with message: since version 4.0 Use DB::get_conn instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1655
        $table = 'Payment';
1656
        if ($db->hasTable('_obsolete_Payment') && !$db->hasTable('Payment')) {
0 ignored issues
show
Deprecated Code introduced by
The method SS_Database::hasTable() has been deprecated with message: since version 4.0 Use DB::get_schema()->hasTable() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1657
            $table = '_obsolete_Payment';
1658
            $this->DBAlterationMessageNow('The table Payment has been moved to _obsolete_Payment. We are using _obsolete_Payment to fix things...', 'deleted');
1659
        }
1660
        DB::query(
1661
            '
1662
            INSERT IGNORE INTO EcommercePayment(
1663
                `ID`,
1664
                `ClassName`,
1665
                `Created`,
1666
                `LastEdited`,
1667
                `Status`,
1668
                `AmountAmount`,
1669
                `AmountCurrency`,
1670
                `Message`,
1671
                `IP`,
1672
                `ProxyIP`,
1673
                `OrderID`,
1674
                `ExceptionError`,
1675
                `PaidByID`
1676
            )
1677
            SELECT
1678
                    `ID`,
1679
                    `ClassName`,
1680
                    `Created`,
1681
                    `LastEdited`,
1682
                    `Status`,
1683
                    IF(`AmountAmount` > 0, `AmountAmount`, `Amount`),
1684
                    IF(`AmountCurrency` <> \'\', `AmountCurrency`, `Currency`),
1685
                    `Message`,
1686
                    `IP`,
1687
                    `ProxyIP`,
1688
                    `OrderID`,
1689
                    `ExceptionError`,
1690
                    `PaidByID`
1691
                FROM '.$table.''
1692
        );
1693
        $this->DBAlterationMessageNow('Moving Payment to Ecommerce Payment', 'created');
1694
1695
        return 0;
1696
    }
1697
1698
    public function ecommercetaskupgradepickupordeliverymodifier_310()
1699
    {
1700
        $explanation = '
1701
            <h1>310.Upgrade Pick Up of Delivery Modifier</h1>
1702
            <p>Fixing data in this modifier if it exists.</p>
1703
        ';
1704
        if ($this->retrieveInfoOnly) {
1705
            return $explanation;
1706
        } else {
1707
            echo $explanation;
1708
        }
1709
        if (class_exists('EcommerceTaskUpgradePickUpOrDeliveryModifier') && $this->hasTableAndField('PickUpOrDeliveryModifier', 'PickupOrDeliveryType')) {
1710
            $obj = EcommerceTaskUpgradePickUpOrDeliveryModifier::create();
1711
            $obj->run(null);
1712
        }
1713
1714
        return 0;
1715
    }
1716
1717
    public function ecommercetaskupgradepickupordeliverymodifier_320()
1718
    {
1719
        $explanation = '
1720
            <h1>320. Removing empty Order Items</h1>
1721
            <p>Removes all the order items without a buyable.</p>
1722
        ';
1723
        if ($this->retrieveInfoOnly) {
1724
            return $explanation;
1725
        } else {
1726
            echo $explanation;
1727
        }
1728
        $orderItems = OrderItem::get()->filter(array('BuyableID' => 0));
1729
        $count = $orderItems->count();
1730
        if ($count > 0) {
1731
            $style = 'deleted';
1732
        } else {
1733
            $style = 'created';
1734
        }
1735
        $this->DBAlterationMessageNow('There are '.$count.' items that should be removed', $style);
1736
        foreach ($orderItems as $orderItem) {
1737
            $this->DBAlterationMessageNow('Deleting order item with ID: '.$orderItem->ID, 'deleted');
1738
            $orderItem->delete();
1739
        }
1740
1741
        return 0;
1742
    }
1743
1744
    public function removemobilephones_330()
1745
    {
1746
        $explanation = '
1747
            <h1>323. Removing mobile phones</h1>
1748
            <p>Move all Billing and Shipping Address Mobile Phone Entries to Phone.</p>
1749
        ';
1750
        if ($this->retrieveInfoOnly) {
1751
            return $explanation;
1752
        } else {
1753
            echo $explanation;
1754
        }
1755
        $this->DBAlterationMessageNow('Moving Mobile Phone to Phone in Billing Address', 'created');
1756
        DB::query("UPDATE BillingAddress SET Phone = MobilePhone WHERE Phone = '' OR Phone IS NULL;");
1757
1758
        $this->DBAlterationMessageNow('Moving Mobile Phone to Phone in Shipping Address', 'created');
1759
        DB::query("UPDATE ShippingAddress SET ShippingPhone = ShippingMobilePhone WHERE ShippingPhone = '' OR ShippingPhone IS NULL;");
1760
1761
        $this->DBAlterationMessageNow('Merging Mobile Phone and Phone in Billing Address', 'created');
1762
        DB::query("UPDATE BillingAddress SET Phone = CONCAT(Phone, ' ', MobilePhone) WHERE Phone <> '' AND Phone IS NOT NULL AND MobilePhone <> '' AND MobilePhone IS NOT NULL;");
1763
1764
        $this->DBAlterationMessageNow('Merging Mobile Phone and Phone in Shipping Address', 'created');
1765
        DB::query("UPDATE ShippingAddress SET ShippingPhone = CONCAT(ShippingPhone, ' ', ShippingMobilePhone) WHERE ShippingPhone <> '' AND ShippingPhone IS NOT NULL AND ShippingMobilePhone <> '' AND ShippingMobilePhone IS NOT NULL;");
1766
1767
        //remove fields
1768
        $this->DBAlterationMessageNow('Making obsolete: BillingAddress.MobilePhone', 'deleted');
1769
        $this->makeFieldObsolete('BillingAddress', 'MobilePhone');
1770
1771
        $this->DBAlterationMessageNow('Making obsolete: ShippingAddress.ShippingMobilePhone', 'deleted');
1772
        $this->makeFieldObsolete('ShippingAddress', 'ShippingMobilePhone');
1773
1774
        return 0;
1775
    }
1776
1777
    public function theEnd_9999()
1778
    {
1779
        $explanation = '
1780
            <h1>9999. Migration Completed</h1>
1781
        ';
1782
        if ($this->retrieveInfoOnly) {
1783
            return $explanation;
1784
        } else {
1785
            echo $explanation;
1786
        }
1787
1788
        return 0;
1789
    }
1790
1791
    public function DBAlterationMessageNow($message, $style = '')
1792
    {
1793
        DB::alteration_message($message, $style);
1794
        ob_end_flush();
1795
        ob_start();
1796
    }
1797
}
1798