Passed
Branch master (8d4084)
by Antony
03:09 queued 01:05
created

UnleashedUpdateProductTask   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 116
dl 0
loc 177
rs 10
c 0
b 0
f 0
wmc 23

1 Method

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