UnleashedUpdateProductTask   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 182
Duplicated Lines 0 %

Importance

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

1 Method

Rating   Name   Duplication   Size   Complexity  
F run() 0 174 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 DateTime;
11
use DateTimeZone;
12
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...
13
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...
14
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...
15
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...
16
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...
17
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...
18
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...
19
20
/**
21
 * Update Products with fresh data from Unleashed Inventory Management Software
22
 */
23
abstract class UnleashedUpdateProductTask extends UnleashedBuildTask
24
{
25
    protected $title = "Unleashed: Update Products";
26
27
    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.";
28
29
    protected string $email_subject = "API Unleashed Software - Update Product Results";
30
31
    public function run($request): void
32
    {
33
        // Definitions
34
        $silvershopInternalItemIDMustBeUnique = Product::get()->column('InternalItemID');
35
        $silvershopTitleMustBeUnique = Product::get()->column('Title');
36
        $consumer = Consumer::get()->find('Title', 'ProductUpdate');
37
38
        // Get Products from Unleashed
39
        if (!$consumer) {
40
            $response = UnleashedAPI::sendCall(
41
                'GET',
42
                'https://api.unleashedsoftware.com/Products'
43
            );
44
45
            $apidata_array = (array) json_decode((string) $response->getBody(), true);
46
            $apidata = $apidata_array['Items'];
47
            $pagination = $apidata_array['Pagination'];
48
            $numberofpages = (int) $pagination['NumberOfPages'];
49
50
            if ($numberofpages > 1) {
51
                for ($i = 2; $i <= $numberofpages; $i++) {
52
                    $response = UnleashedAPI::sendCall(
53
                        'GET',
54
                        'https://api.unleashedsoftware.com/Products/' . $i
55
                    );
56
                    $apidata_array = (array) json_decode((string) $response->getBody(), true);
57
                    $apidata = array_merge($apidata, $apidata_array['Items']);
58
                }
59
            }
60
        } else {
61
            $query = [];
62
            $dateTime = new DateTime($consumer->getField('ExternalLastEdited'));
63
            $dateTime->setTimezone(new DateTimeZone("UTC"));  // required only for Unleashed Products (not for other endpoints)
64
            $query['modifiedSince'] = substr($dateTime->format('Y-m-d\TH:i:s.u'), 0, 23);
65
66
            $response = UnleashedAPI::sendCall(
67
                'GET',
68
                'https://api.unleashedsoftware.com/Products',
69
                ['query' => $query]
70
            );
71
72
            $apidata_array = (array) json_decode((string) $response->getBody()->getContents(), true);
73
            $apidata = $apidata_array['Items'];
74
            $pagination = $apidata_array['Pagination'];
75
            $numberofpages = (int) $pagination['NumberOfPages'];
76
77
            if ($numberofpages > 1) {
78
                for ($i = 2; $i <= $numberofpages; $i++) {
79
                    $response = UnleashedAPI::sendCall(
80
                        'GET',
81
                        'https://api.unleashedsoftware.com/Products/' . $i,
82
                        ['query' => $query]
83
                    );
84
                    $apidata_array = (array) json_decode((string) $response->getBody()->getContents(), true);
85
                    $apidata = array_merge($apidata, $apidata_array['Items']);
86
                }
87
            }
88
        }
89
90
        $this->log('<h2>Preliminary Checks</h2>');
91
        // Check for duplicates in DataList before proceeding further
92
        $duplicates = Utilities::getDuplicates($silvershopInternalItemIDMustBeUnique);
93
        if ($duplicates !== []) {
94
            echo "<h2>Duplicate check of Product InternalItemID within Silvershop</h2>";
95
            foreach ($duplicates as $duplicate) {
96
                $this->log($duplicate);
97
            }
98
99
            $this->log('Please remove duplicates from Silvershop before running this Build Task');
100
            $this->log('Exit');
101
            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...
102
        }
103
104
        $this->log('No duplicate found');
105
106
        $duplicates = Utilities::getDuplicates($silvershopTitleMustBeUnique);
107
        if ($duplicates !== []) {
108
            echo "<h2>Duplicate check of Product Titles within Silvershop</h2>";
109
            foreach ($duplicates as $duplicate) {
110
                $this->log($duplicate);
111
            }
112
113
            $this->log('Please remove duplicates from Silvershop before running this Build Task');
114
            $this->log('Exit');
115
            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...
116
        }
117
118
        $this->log('No duplicate found');
119
120
        // Check for duplicates in apidata before proceeding further
121
        $duplicates = Utilities::getDuplicates(array_column($apidata, 'ProductCode'));
122
        if ($duplicates !== []) {
123
            echo "<h2>Duplicate check of ProductCode within Unleashed</h2>";
124
            foreach ($duplicates as $duplicate) {
125
                $this->log(htmlspecialchars((string) $duplicate, ENT_QUOTES, 'utf-8'));
126
            }
127
128
            $this->log(
129
                'Please remove duplicates from Unleashed before running this Build Task'
130
            );
131
            $this->log('Exit');
132
            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...
133
        }
134
135
        $this->log('No duplicate found');
136
137
        // Update
138
        $this->log('<h3>Update Product records in Silvershop</h3>');
139
        $productBulkLoader = ProductBulkLoader::create(Product::class);
140
        $productBulkLoader->transforms = [
141
            'Parent' => [
142
                'callback' => function (array $value) {
143
                    $obj = ProductCategory::get()->find('Guid', $value['Guid']);
144
                    if ($obj) {
145
                        return $obj;
146
                    }
147
148
                    return ProductCategory::get()->find('Title', $value['GroupName']);
149
                }
150
            ],
151
            'BasePrice' => [
152
                'callback' => fn($value): float => (float)$value
153
            ],
154
            'Title' => [
155
                'callback' => function ($value, &$placeholder) {
156
                    $placeholder->URLSegment = Convert::raw2url($value);
157
                    return $value;
158
                }
159
            ]
160
        ];
161
        $bulkLoaderResult = $productBulkLoader->updateRecords($apidata, $this->preview);
162
163
        if ($bulkLoaderResult->UpdatedCount()) {
164
            $this->log(Debug::text($bulkLoaderResult->getData()));
165
        }
166
167
        $this->log("Done");
168
        Debug::show($bulkLoaderResult->Count());
169
        Debug::show(!$this->preview);
170
        Debug::show(Email::config()->get('admin_email'));
171
        Debug::show($this->email_subject);
172
        // Send email
173
        if ($bulkLoaderResult->Count() && !$this->preview && Email::config()->get('admin_email') && $this->email_subject) {
174
            // send email
175
            $email = Email::create(
176
                ShopConfigExtension::config()->get('email_from') ?: Email::config()->get('admin_email'),
177
                Email::config()->get('admin_email'),
178
                $this->email_subject,
179
                Debug::text($bulkLoaderResult->getData())
180
            );
181
182
            $dispatched = true;
183
            try {
184
                $email->send();
185
            } catch (TransportExceptionInterface $e) {
186
                $dispatched = false;
187
                $this->log("Email not sent: " . $e->getDebug());
188
            } finally {
189
                if ($dispatched) {
190
                    $this->log("Email sent");
191
                }
192
            }
193
        }
194
195
        if (!$this->preview && $apidata) {
196
            if (!$consumer) {
197
                $consumer = Consumer::create([
198
                    'Title' => 'ProductUpdate',
199
                    'ExternalLastEditedKey' => 'LastModifiedOn'
200
                ]);
201
            }
202
203
            $consumer->setMaxExternalLastEdited($apidata);
204
            $consumer->write();
205
        }
206
    }
207
}
208