UnleashedUpdateProductTask   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 121
dl 0
loc 177
rs 10
c 2
b 0
f 0
wmc 24

1 Method

Rating   Name   Duplication   Size   Complexity  
F run() 0 169 24
1
<?php
2
3
namespace AntonyThorpe\SilverShopUnleashed\Task;
4
5
use AntonyThorpe\Consumer\Consumer;
0 ignored issues
show
Bug introduced by
The type AntonyThorpe\Consumer\Consumer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use AntonyThorpe\Consumer\Utilities;
0 ignored issues
show
Bug introduced by
The type AntonyThorpe\Consumer\Utilities was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use AntonyThorpe\SilverShopUnleashed\BulkLoader\ProductBulkLoader;
8
use AntonyThorpe\SilverShopUnleashed\Task\UnleashedBuildTask;
9
use AntonyThorpe\SilverShopUnleashed\UnleashedAPI;
10
use DateTimeZone;
11
use SilverShop\Extension\ShopConfigExtension;
0 ignored issues
show
Bug introduced by
The type SilverShop\Extension\ShopConfigExtension was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use SilverShop\Page\Product;
0 ignored issues
show
Bug introduced by
The type SilverShop\Page\Product was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use SilverShop\Page\ProductCategory;
0 ignored issues
show
Bug introduced by
The type SilverShop\Page\ProductCategory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use SilverStripe\Control\Email\Email;
0 ignored issues
show
Bug introduced by
The type SilverStripe\Control\Email\Email was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use SilverStripe\Core\Convert;
0 ignored issues
show
Bug introduced by
The type SilverStripe\Core\Convert was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use SilverStripe\Dev\Debug;
0 ignored issues
show
Bug introduced by
The type SilverStripe\Dev\Debug was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Mailer...sportExceptionInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
19
/**
20
 * Update Products with fresh data from Unleashed Inventory Management Software
21
 */
22
abstract class UnleashedUpdateProductTask extends UnleashedBuildTask
23
{
24
    protected $title = "Unleashed: Update Products";
25
26
    protected $description = "Update the Products in Silvershop with data from Unleashed.  Will not automatically bring over new items but will update Titles, Base Price, etc.";
27
28
    protected string $email_subject = "API Unleashed Software - Update Product Results";
29
30
    public function run($request)
31
    {
32
        // Definitions
33
        $silvershopInternalItemIDMustBeUnique = Product::get()->column('InternalItemID');
34
        $silvershopTitleMustBeUnique = Product::get()->column('Title');
35
        $consumer = Consumer::get()->find('Title', 'ProductUpdate');
36
37
        // Get Products from Unleashed
38
        if (!$consumer) {
39
            $response = UnleashedAPI::sendCall(
40
                'GET',
41
                'https://api.unleashedsoftware.com/Products'
42
            );
43
44
            $apidata_array = (array) json_decode($response->getBody(), true);
45
            $apidata = $apidata_array['Items'];
46
            $pagination = $apidata_array['Pagination'];
47
            $numberofpages = (int) $pagination['NumberOfPages'];
48
49
            if ($numberofpages > 1) {
50
                for ($i = 2; $i <= $numberofpages; $i++) {
51
                    $response = UnleashedAPI::sendCall(
52
                        'GET',
53
                        'https://api.unleashedsoftware.com/Products/' . $i
54
                    );
55
                    $apidata_array = (array) json_decode($response->getBody(), true);
56
                    $apidata = array_merge($apidata, $apidata_array['Items']);
57
                }
58
            }
59
        } else {
60
            $query = [];
61
            $date = new DateTime($consumer->ExternalLastEdited);
0 ignored issues
show
Bug introduced by
The type AntonyThorpe\SilverShopUnleashed\Task\DateTime was not found. Did you mean DateTime? If so, make sure to prefix the type with \.
Loading history...
62
            $date->setTimezone(new DateTimeZone("UTC"));  // required for Unleashed Products (not for other endpoints)
63
            $query['modifiedSince'] = substr($date->format('Y-m-d\TH:i:s.u'), 0, 23);
64
65
            $response = UnleashedAPI::sendCall(
66
                'GET',
67
                'https://api.unleashedsoftware.com/Products',
68
                ['query' => $query]
69
            );
70
71
            $apidata_array = (array) json_decode($response->getBody()->getContents(), true);
72
            $apidata = $apidata_array['Items'];
73
            $pagination = $apidata_array['Pagination'];
74
            $numberofpages = (int) $pagination['NumberOfPages'];
75
76
            if ($numberofpages > 1) {
77
                for ($i = 2; $i <= $numberofpages; $i++) {
78
                    $response = UnleashedAPI::sendCall(
79
                        'GET',
80
                        'https://api.unleashedsoftware.com/Products/' . $i,
81
                        ['query' => $query]
82
                    );
83
                    $apidata_array = (array) json_decode($response->getBody()->getContents(), true);
84
                    $apidata = array_merge($apidata, $apidata_array['Items']);
85
                }
86
            }
87
        }
88
89
        $this->log('<h2>Preliminary Checks</h2>');
90
        // Check for duplicates in DataList before proceeding further
91
        $duplicates = Utilities::getDuplicates($silvershopInternalItemIDMustBeUnique);
92
        if ($duplicates !== []) {
93
            echo "<h2>Duplicate check of Product InternalItemID within Silvershop</h2>";
94
            foreach ($duplicates as $duplicate) {
95
                $this->log($duplicate);
96
            }
97
            $this->log('Please remove duplicates from Silvershop before running this Build Task');
98
            $this->log('Exit');
99
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
100
        } else {
101
            $this->log('No duplicate found');
102
        }
103
104
        $duplicates = Utilities::getDuplicates($silvershopTitleMustBeUnique);
105
        if ($duplicates !== []) {
106
            echo "<h2>Duplicate check of Product Titles within Silvershop</h2>";
107
            foreach ($duplicates as $duplicate) {
108
                $this->log($duplicate);
109
            }
110
            $this->log('Please remove duplicates from Silvershop before running this Build Task');
111
            $this->log('Exit');
112
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
113
        } else {
114
            $this->log('No duplicate found');
115
        }
116
117
        // Check for duplicates in apidata before proceeding further
118
        $duplicates = Utilities::getDuplicates(array_column($apidata, 'ProductCode'));
119
        if ($duplicates !== []) {
120
            echo "<h2>Duplicate check of ProductCode within Unleashed</h2>";
121
            foreach ($duplicates as $duplicate) {
122
                $this->log(htmlspecialchars((string) $duplicate, ENT_QUOTES, 'utf-8'));
123
            }
124
            $this->log(
125
                'Please remove duplicates from Unleashed before running this Build Task'
126
            );
127
            $this->log('Exit');
128
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
129
        } else {
130
            $this->log('No duplicate found');
131
        }
132
133
        // Update
134
        $this->log('<h3>Update Product records in Silvershop</h3>');
135
        $loader = ProductBulkLoader::create(Product::class);
136
        $loader->transforms = [
137
            'Parent' => [
138
                'callback' => function (array $value) {
139
                    $obj = ProductCategory::get()->find('Guid', $value['Guid']);
140
                    if ($obj) {
141
                        return $obj;
142
                    } else {
143
                        return ProductCategory::get()->find('Title', $value['GroupName']);
144
                    }
145
                }
146
            ],
147
            'BasePrice' => [
148
                'callback' => fn($value): float => (float)$value
149
            ],
150
            'Title' => [
151
                'callback' => function ($value, &$placeholder) {
152
                    $placeholder->URLSegment = Convert::raw2url($value);
153
                    return $value;
154
                }
155
            ]
156
        ];
157
        $results = $loader->updateRecords($apidata, $this->preview);
158
159
        if ($results->UpdatedCount()) {
160
            $this->log(Debug::text($results->getData()));
161
        }
162
        $this->log("Done");
163
        Debug::show($results->Count());
164
        Debug::show(!$this->preview);
165
        Debug::show(Email::config()->admin_email);
166
        Debug::show($this->email_subject);
167
        // Send email
168
        if ($results->Count() && !$this->preview && Email::config()->admin_email && $this->email_subject) {
169
            // send email
170
            $email = Email::create(
171
                ShopConfigExtension::config()->email_from ?: Email::config()->admin_email,
172
                Email::config()->admin_email,
173
                $this->email_subject,
174
                Debug::text($results->getData())
175
            );
176
177
            $dispatched = true;
178
            try {
179
                $email->send();
180
            } catch (TransportExceptionInterface $e) {
181
                $dispatched = false;
182
                $this->log("Email not sent: " . $e->getDebug());
183
            } finally {
184
                if ($dispatched) {
185
                    $this->log("Email sent");
186
                }
187
            }
188
        }
189
190
        if (!$this->preview && $apidata) {
191
            if (!$consumer) {
192
                $consumer = Consumer::create([
193
                    'Title' => 'ProductUpdate',
194
                    'ExternalLastEditedKey' => 'LastModifiedOn'
195
                ]);
196
            }
197
            $consumer->setMaxExternalLastEdited($apidata);
198
            $consumer->write();
199
        }
200
    }
201
}
202