Here is the full function. I double checked Git commit history, and this code has not changed since May. It runs every night which I know as it emails me... If helpful it's comparing information on our webstore to information in our ERP system to identify any possible discrepancies between the two, and sends an email notifying us of any discrepencies...
public function handle()
{
$discrepTable = "";
$errors = [];
$differencesFound = false;
Log::channel('epicorLog')->info($this->signature . ": " . $this->description);
$columns = ['part_name', 'quantity', 'price_before', 'price_after', 'comments'];
$discrepTable .= "<table border=1><tr>";
foreach($columns as $column) $discrepTable .= "<th>$column</th>";
$discrepTable .= "</tr>";
//TODO this harcodes a pricelist, make the BAQ smarter to chose the correct price
//price list based on expiration date
$ePriceList = EpicorRepository::getPriceList();
$parts = Part::notOrphaned()
->active()
//->notIgnored()
->associatedWithSellableProduct()
->get();
//$parts = Part::where('name', 'like', 'TS-7800-V2-DMN1I')->get();
$partsUpdated = collect();
$partsWithIssues = collect();
foreach($parts as $part) {
if ($ePriceList->contains('name', $part->name)) {
//Warning - the BAQ does not filter out any expired prices nor does this code
$epicorPartPricing = $ePriceList->filter(function ($value, $key) use ($part) {
return ($value->name == $part->name) &&
($value->quantity <= 100) &&
//TODO make the BAQ smarter so we don't have to do this type of a check
($value->listCode == "Master3");
});
if($epicorPartPricing->count() == 0) {
$differencesFound = true;
$msg = "Part $part->name didn't have any pricing in Epicor.";
Log::channel('epicorLog')->error("$msg Cowardly skipping...");
$errors[] = $msg;
$discrepTable .= "<tr>" .
"<td>" . $part->name . "</td>" .
"<td></td>" .
"<td></td>" .
"<td></td>" .
"<td>$msg</td>" .
"</tr>";
continue;
}
$partPrices = collect();
$quantities = [];
// Gather all the price breaks to be able to determine max_quantity
foreach($epicorPartPricing as $epicorPartPrice) {
$quantities[] = $epicorPartPrice->PLPartBrk_Quantity;
}
foreach($epicorPartPricing as $epicorPartPrice) {
$min_quantity = $epicorPartPrice->PLPartBrk_Quantity;
$max_quantity = 99999;
$qty_array_index = array_search($min_quantity, $quantities);
if (isset($quantities[$qty_array_index + 1])) {
$max_quantity = $quantities[$qty_array_index + 1] - 1;
}
$partPrices->push(new PartPrice([
'min_quantity' => (integer)$min_quantity,
'max_quantity' => (integer)$max_quantity,
'price' => (double)$epicorPartPrice->PLPartBrk_UnitPrice,
'part_id' => $part->id,
'is_unavailable' => (boolean)$epicorPartPrice->PLPartBrk_callUs_c,
]));
}
$clonePrices = clone $part->prices;
try {
\DB::beginTransaction();
$part->prices()->delete();
$part->prices()->saveMany($partPrices);
\DB::commit();
}
catch(Throwable $e) {
$msg = "$part->name threw error:\n$e";
Log::channel('epicorLog')->error(" Error! Rolling back changes because:\n$e");
$errors[] = $msg;
$discrepTable .= "<tr>" .
"<td>" . $part->name . "</td>" .
"<td></td>" .
"<td></td>" .
"<td></td>" .
"<td>$msg</td>" .
"</tr>";
\DB::rollback();
continue;
}
$part->refresh();
// Compare after with before to get any new or updated pricing.
$part->prices->each(function($partPrice, $index) use ($part, $clonePrices) {
$qty = $partPrice->min_quantity;
$beforePartPrice = $clonePrices->where('min_quantity', $qty)->first();
if(!$beforePartPrice) {
$differencesFound = 1;
Log::channel('epicorLog')->info("For qty $qty, before: null, after: $partPrice->price");
$discrepTable .= "<tr>" .
"<td>" . $part->name . "</td>" .
"<td>" . $qty . "</td>" .
"<td></td>" .
"<td>" . $partPrice->price . "</td>" .
"<td>Pricing for this quantity was added</td>" .
"</tr>";
}
else if ($beforePartPrice->price != $partPrice->price) {
$differencesFound = true;
Log::channel('epicorLog')->info("For qty $qty, before: $beforePartPrice->price, after: $partPrice->price");
$discrepTable .= "<tr>" .
"<td>" . $part->name . "</td>" .
"<td>" . $qty . "</td>" .
"<td>" . $beforePartPrice->price . "</td>" .
"<td>" . $partPrice->price . "</td>" .
"<td>Updated Pricing</td>" .
"</tr>";
}
if($beforePartPrice && ((boolean)$beforePartPrice->is_unavailable !== (boolean)$partPrice->is_unavailable)) {
$differencesFound = true;
$beforeStr = (boolean)$beforePartPrice->is_unavailable ? "Yes" : "No";
$afterStr = (boolean)$partPrice->is_unavailable ? "Yes" : "No";
Log::channel('epicorLog')->info("For qty $qty, is_unavailable before: $beforeStr, after: $afterStr");
$discrepTable .= "<tr>" .
"<td>" . $part->name . "</td>" .
"<td>" . $qty . "</td>" .
"<td> </td>" .
"<td></td>" .
"<td>Changed 'Call Us' state from '$beforeStr' to '$afterStr'</td>" .
"</tr>";
}
});
// Quick compare before with after to see if any removed pricing
$clonePrices->each(function($clonePartPrice, $index) use ($part) {
$qty = $clonePartPrice->min_quantity;
$afterPartPrice = $part->prices->where('min_quantity', $qty)->first();
if(!$afterPartPrice) {
Log::channel('epicorLog')->info("For qty $qty, before: $clonePartPrice->price, after: null");
$discrepTable .= "<tr>" .
"<td>" . $part->name . "</td>" .
"<td>" . $qty . "</td>" .
"<td>" . $clonePartPrice->price . "</td>" .
"<td></td>" .
"<td>Pricing for this quantity was removed</td>" .
"</tr>";
}
});
}
else {
Log::channel('epicorLog')->info("...Skipping no pricelist information.");
}
}
Cache::tags('pricing')->flush();
Log::channel('epicorLog')->info("Cleared pricing cache for products.");
// If there's more than one line in the file (header), then we want to report it
if($differencesFound) {
$msg = new GenericMessage();
$to = ['[email protected]'];
$msg->subject = 'Part Pricing Updated on Web Based on Epicor Data: ' . count($errors) . " errors detected";
$msg->content = "<h1>Errors</h1>";
foreach($errors as $error) $msg->content .= "<li>$error</li>";
$msg->content .= "</ul><br />";
$msg->content .= "<h1>Error Details</h1>";
$msg->content .= $discrepTable;
if(\App::environment('local')) {
$to = [env('DEVELOPER_EMAIL')];
}
Log::channel('epicorLog')->info("Part pricing updated and sent via email to " . implode(', ', $to) . " for review.");
Mail::to($to)->queue($msg);
}
else {
Log::channel('epicorLog')->info("No part pricing updates detected, so not sending an email.");
}
}