|
|
|
|
|
|
|
|
|
vaJSGYdIOFTRc96w
vaJSGYdIOFTRc96w
|
|
Spread sale dates over last 2 months (direct date update, skip missing contacts)
Spread sale dates over last 2 months (direct date update, skip missing contacts)
|
|
<?php
// Spread all sales over the last 2 months (2026-07-05 → 2026-09-04) with realistic date/time distribution.
// Uses saveColumn() so we only touch sale_datetime and don't re-trigger full sale validation
// (full save() previously failed on a sale linked to a deleted contact).
$arrSales = \Components\Commerce\Sales::getAll(['start' => 0, 'limit' => 500]);
echo "Found " . count($arrSales) . " sales.\n";
$iStart = strtotime('2026-07-05 08:30:00');
$iEnd = strtotime('2026-09-04 19:00:00');
$iCount = 0;
$iReceipts = 0;
$arrErrors = [];
foreach ($arrSales as $arrSale)
{
$iSaleId = $arrSale['sale_id'];
// Pick a random timestamp, weighted toward weekdays and business hours for realism.
$iTimestamp = 0;
for ($iTry = 0; $iTry < 20; $iTry++)
{
$iCandidate = mt_rand($iStart, $iEnd);
$iDow = (int)date('N', $iCandidate); // 1 = Mon ... 7 = Sun
$iHour = (int)date('G', $iCandidate);
// Keep weekday candidates, and allow weekends with lower probability.
if ($iDow <= 5 || mt_rand(1, 4) === 1)
{
// Keep mostly business-hours candidates; evening/early-morning with lower probability.
if (($iHour >= 8 && $iHour <= 20) || mt_rand(1, 5) === 1)
{
$iTimestamp = $iCandidate;
break;
}
}
}
if ($iTimestamp === 0)
{
$iTimestamp = mt_rand($iStart, $iEnd);
}
$strNewDate = date('Y-m-d H:i:s', $iTimestamp);
try
{
\Components\Commerce\Sales::saveColumn($iSaleId, 'sale_datetime', $strNewDate);
$iCount++;
}
catch (\Exception $e)
{
$arrErrors[] = "Sale #{$iSaleId}: " . $e->getMessage();
continue;
}
// For paid sales, move the payment receipt(s) to shortly after the sale time so payment history stays consistent.
if ($arrSale['sale_receipt_status'] === 'paid')
{
$arrReceipts = \Components\Commerce\Sales\Receipts::getAll([
'filter' => [['receipt_parent_id', '=', $iSaleId]],
]);
foreach ($arrReceipts as $arrReceipt)
{
try
{
$strReceiptDate = date('Y-m-d H:i:s', $iTimestamp + mt_rand(60, 7200)); // 1 min – 2 hrs after sale
\Components\Commerce\Sales\Receipts::saveColumn($arrReceipt['receipt_id'], 'receipt_datetime', $strReceiptDate);
$iReceipts++;
}
catch (\Exception $e)
{
$arrErrors[] = "Receipt #{$arrReceipt['receipt_id']}: " . $e->getMessage();
}
}
}
if ($iCount % 25 === 0)
{
\Components\Settings\Developer\Threads::setCurrentProgressStatus("Updated {$iCount} / " . count($arrSales) . " sales…");
}
}
echo "Updated sale_datetime on {$iCount} sales (range: 5 Jul 2026 → 4 Sep 2026).\n";
echo "Moved {$iReceipts} payment receipts to match their sales.\n";
if (count($arrErrors))
{
echo "Errors (" . count($arrErrors) . "):\n" . implode("\n", array_slice($arrErrors, 0, 20)) . "\n";
}
<?php
// Spread all sales over the last 2 months (2026-07-05 → 2026-09-04) with realistic date/time distribution.
// Uses saveColumn() so we only touch sale_datetime and don't re-trigger full sale validation
// (full save() previously failed on a sale linked to a deleted contact).
$arrSales = \Components\Commerce\Sales::getAll(['start' => 0, 'limit' => 500]);
echo "Found " . count($arrSales) . " sales.\n";
$iStart = strtotime('2026-07-05 08:30:00');
$iEnd = strtotime('2026-09-04 19:00:00');
$iCount = 0;
$iReceipts = 0;
$arrErrors = [];
foreach ($arrSales as $arrSale)
{
$iSaleId = $arrSale['sale_id'];
// Pick a random timestamp, weighted toward weekdays and business hours for realism.
$iTimestamp = 0;
for ($iTry = 0; $iTry < 20; $iTry++)
{
$iCandidate = mt_rand($iStart, $iEnd);
$iDow = (int)date('N', $iCandidate); // 1 = Mon ... 7 = Sun
$iHour = (int)date('G', $iCandidate);
// Keep weekday candidates, and allow weekends with lower probability.
if ($iDow <= 5 || mt_rand(1, 4) === 1)
{
// Keep mostly business-hours candidates; evening/early-morning with lower probability.
if (($iHour >= 8 && $iHour <= 20) || mt_rand(1, 5) === 1)
{
$iTimestamp = $iCandidate;
break;
}
}
}
if ($iTimestamp === 0)
{
$iTimestamp = mt_rand($iStart, $iEnd);
}
$strNewDate = date('Y-m-d H:i:s', $iTimestamp);
try
{
\Components\Commerce\Sales::saveColumn($iSaleId, 'sale_datetime', $strNewDate);
$iCount++;
}
catch (\Exception $e)
{
$arrErrors[] = "Sale #{$iSaleId}: " . $e->getMessage();
continue;
}
// For paid sales, move the payment receipt(s) to shortly after the sale time so payment history stays consistent.
if ($arrSale['sale_receipt_status'] === 'paid')
{
$arrReceipts = \Components\Commerce\Sales\Receipts::getAll([
'filter' => [['receipt_parent_id', '=', $iSaleId]],
]);
foreach ($arrReceipts as $arrReceipt)
{
try
{
$strReceiptDate = date('Y-m-d H:i:s', $iTimestamp + mt_rand(60, 7200)); // 1 min – 2 hrs after sale
\Components\Commerce\Sales\Receipts::saveColumn($arrReceipt['receipt_id'], 'receipt_datetime', $strReceiptDate);
$iReceipts++;
}
catch (\Exception $e)
{
$arrErrors[] = "Receipt #{$arrReceipt['receipt_id']}: " . $e->getMessage();
}
}
}
if ($iCount % 25 === 0)
{
\Components\Settings\Developer\Threads::setCurrentProgressStatus("Updated {$iCount} / " . count($arrSales) . " sales…");
}
}
echo "Updated sale_datetime on {$iCount} sales (range: 5 Jul 2026 → 4 Sep 2026).\n";
echo "Moved {$iReceipts} payment receipts to match their sales.\n";
if (count($arrErrors))
{
echo "Errors (" . count($arrErrors) . "):\n" . implode("\n", array_slice($arrErrors, 0, 20)) . "\n";
}
|
|
|
|
2026-09-04 21:31:32
2026-09-04 21:31:32
|
|
|
|
This script rewrites the dates on your sales records to make them look like they happened naturally over a two-month period.
**What it changes:**
1. **Up to 500 sales records** — every sale gets a brand-new date and time, picked at random from between 5 July 2026 and 4 September 2026. The dates aren't purely random, though: most will land on weekdays between 8am and 8pm, with only a small number falling on weekends or late at night, so the pattern looks like real shop activity.
2. **Payment receipts for paid sales** — for any sale marked as paid, the payment record is also given a new date, set shortly after the sale's new date (between 1 minute and 2 hours later). This keeps the payment history looking sensible — payments always appear to come in just after the sale.
**What it does not change:**
- Nothing is added or deleted. The sales, their items, customers, and amounts all stay exactly as they are — only the dates and times are replaced.
- Any sale that can't be updated is skipped and noted, rather than stopping the whole run.
**In short:** after running this, your sales history will show up to 500 sales spread realistically across July and August 2026, with matching payment dates — but the actual sales content is untouched.
This script rewrites the dates on your sales records to make them look like they happened naturally over a two-month period.
**What it changes:**
1. **Up to 500 sales records** — every sale gets a brand-new date and time, picked at random from between 5 July 2026 and 4 September 2026. The dates aren't purely random, though: most will land on weekdays between 8am and 8pm, with only a small number falling on weekends or late at night, so the pattern looks like real shop activity.
2. **Payment receipts for paid sales** — for any sale marked as paid, the payment record is also given a new date, set shortly after the sale's new date (between 1 minute and 2 hours later). This keeps the payment history looking sensible — payments always appear to come in just after the sale.
**What it does not change:**
- Nothing is added or deleted. The sales, their items, customers, and amounts all stay exactly as they are — only the dates and times are replaced.
- Any sale that can't be updated is skipped and noted, rather than stopping the whole run.
**In short:** after running this, your sales history will show up to 500 sales spread realistically across July and August 2026, with matching payment dates — but the actual sales content is untouched.
|
|
|
|
|