Completed
Branch master (e42d77)
by Antony
03:02
created

UnleashedUpdateProductTask   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 178
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 117
dl 0
loc 178
rs 10
c 0
b 0
f 0
wmc 23

1 Method

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