fannie/modules/plugins2.0/RP/RpOrderPage.php
<?php
include(__DIR__ . '/../../../config.php');
if (!class_exists('FannieAPI')) {
include(__DIR__ . '/../../../classlib2.0/FannieAPI.php');
}
if (!class_exists('RpOrderCategoriesModel')) {
include(__DIR__ . '/models/RpOrderCategoriesModel.php');
}
if (!class_exists('RpOrderItemsModel')) {
include(__DIR__ . '/models/RpOrderItemsModel.php');
}
if (!class_exists('RpSessionsModel')) {
include(__DIR__ . '/models/RpSessionsModel.php');
}
if (!class_exists('RpSnapshotsModel')) {
include(__DIR__ . '/models/RpSnapshotsModel.php');
}
class RpOrderPage extends FannieRESTfulPage
{
protected $header = 'Daily Order Guide';
protected $title = 'Daily Order Guide';
protected $must_authenticate = true;
public function preprocess()
{
$this->addRoute('get<searchVendor>', 'get<searchLC>', 'get<json>', 'get<date1><date2>', 'get<clear>', 'post<json>');
$this->userID = FannieAuth::getUID($this->current_user);
return parent::preprocess();
}
protected function get_clear_handler()
{
unset($_SESSION['rpState']);
$model = new RpSessionsModel($this->connection);
$model->userID($this->userID);
$model->dataType('RP');
$model->load();
$snap = new RpSnapshotsModel($this->connection);
$snap->userID($model->userID());
$snap->tdate(date('Y-m-d H:i:s'));
$snap->data($model->data());
$snap->dataType($model->dataType());
$snap->save();
$model->delete();
return 'RpOrderPage.php';
}
protected function get_date1_date2_handler()
{
$date1 = date('Y-m-d', strtotime(FormLib::get('date1')));
$date2 = date('Y-m-d', strtotime(FormLib::get('date2')));
$args = array(FormLib::get('store'), $date1, $date2);
$ignore = 'CASE WHEN receivedDate < ' . $this->connection->curdate() . ' THEN 1 ELSE 0 END AS ignored';
/**
* Check for past dates. Since the purpose it to view future expected
* deliveries, selected weekdays that are in the past should be pushed
* forward into the subsequent week
*/
$ts1 = strtotime($date1);
$ts2 = strtotime($date2);
$today = strtotime(date('Y-m-d'));
if ($ts1 < $today) {
$ts1 = mktime(0, 0, 0, date('n', $ts1), date('j', $ts1) + 7, date('Y', $ts1));
}
if ($ts2 < $today) {
$ts2 = mktime(0, 0, 0, date('n', $ts2), date('j', $ts2) + 7, date('Y', $ts2));
}
if ($ts1 > $ts2) {
$swap = $ts2;
$ts2 = $ts1;
$ts1 = $swap;
}
$date1 = date('Y-m-d', $ts1);
$date2 = date('Y-m-d', $ts2);
$extra = strtotime($date2);
if ($extra) {
$extra = mktime(0,0,0,date('n',$extra),date('j',$extra)+3,date('Y',$extra));
$date3 = date('Y-m-d', $extra);
// safe embed because it's a formatted date string or false
// for any user input
$ignore = "CASE WHEN receivedDate > {$date2} OR receivedDate < " . $this->connection->curdate() . "
THEN 1 ELSE 0 END AS ignored";
$args[2] = $date3;
}
$prep = $this->connection->prepare("SELECT receivedDate, internalUPC AS upc, brand, quantity AS qty, caseSize,
{$ignore}
FROM PurchaseOrderItems AS i
INNER JOIN PurchaseOrder AS o ON i.orderID=o.orderID
WHERE (o.vendorID=-2 OR o.vendorInvoiceID LIKE 'PREBOOK %')
AND o.userID=-99
AND o.placed=1
AND o.storeID=?
AND i.receivedDate IS NOT NULL
AND (
i.receivedDate BETWEEN ? AND ?
OR i.receivedDate = " . $this->connection->curdate() . "
)
ORDER BY i.receivedDate
");
$qtys = $this->connection->getAllRows($prep, $args);
$ret = array();
foreach ($qtys as $row) {
if (!isset($ret[$row['upc']])) {
$ret[$row['upc']] = array('upc' => $row['upc'], 'qty' => 0, 'text' => '');
}
if ($row['caseSize'] > 1) {
$row['qty'] *= $row['caseSize'];
}
if ($row['ignored'] != 1) {
$ret[$row['upc']]['qty'] += $row['qty'];
}
if ($ret[$row['upc']]['text'] != '') {
$ret[$row['upc']]['text'] .= '<br />';
}
$ts = strtotime($row['receivedDate']);
$text = date('n/j', $ts) . ' ' . $row['qty'] . ' ' . $row['brand'];
$ret[$row['upc']]['text'] .= $text;
}
$dekey = array();
foreach ($ret as $upc => $row) {
$dekey[] = $row;
}
echo json_encode($dekey);
return false;
}
protected function post_json_handler()
{
return $this->get_json_handler();
}
protected function get_json_handler()
{
$_SESSION['rpState'] = json_decode($this->json, true);
$model = new RpSessionsModel($this->connection);
$model->userID($this->userID);
$model->dataType('RP');
$model->data($this->json);
$model->save();
var_dump($_SESSION['rpState']);
echo 'OK';
return false;
}
protected function get_searchLC_handler()
{
$prep = $this->connection->prepare("SELECT * FROM likeCodes WHERE likeCodeDesc LIKE ?");
$res = $this->connection->getAllRows($prep, array('%' . $this->searchLC . '%'));
$ret = array();
foreach ($res as $row) {
$ret[] = array(
'label' => $row['likeCodeDesc'],
'value' => $row['likeCode'],
);
}
echo json_encode($ret);
return false;
}
protected function get_searchVendor_handler()
{
$query = "SELECT * FROM vendorItems WHERE (description LIKE ? OR brand LIKE ?)";
$args = array('%' . $this->searchVendor . '%', '%' . $this->searchVendor . '%');
if (FormLib::get('vendorID')) {
$args[] = FormLib::get('vendorID');
$query .= ' AND vendorID=?';
} else {
$query .= ' AND vendorID IN (292, 293, 136)';
}
$query = "SELECT p.upc, p.description, v.sku, v.units, v.vendorID, u.likeCode, p.cost
FROM products AS p
INNER JOIN MasterSuperDepts AS m ON p.department=m.dept_ID
LEFT JOIN vendorItems AS v ON p.default_vendor_id=v.vendorID AND p.upc=v.upc
LEFT JOIN upcLike AS u ON u.upc=p.upc
WHERE p.store_id=1
AND m.superID=6
AND (p.brand LIKE ? OR p.description LIKE ?)
ORDER BY CASE WHEN likeCode IS NULL THEN 1 ELSE 0 END,
p.description
";
$args = array('%' . $this->searchVendor . '%', '%' . $this->searchVendor . '%');
$ret = array();
$prep = $this->connection->prepare($query);
$res = $this->connection->execute($prep, $args);
while ($row = $this->connection->fetchRow($res)) {
$label = $row['description'];
if ($row['likeCode']) {
$label .= ' (LC' . $row['likeCode'] . ')';
}
if ($row['vendorID'] == 28) {
$row['vendorID'] = 292;
} elseif ($row['vendorID'] == 25) {
$row['vendorID'] = 293;
}
if ($row['units'] == 0) {
$row['units'] = 1;
}
$value = array(
'vendorID' => $row['vendorID'],
'caseSize' => $row['units'],
'sku' => $row['sku'],
'upc' => $row['upc'],
'item' => $row['description'],
'likeCode' => $row['likeCode'],
'cost' => $row['cost'] * $row['units'],
);
$value = json_encode($value);
$ret[] = array(
'label' => $label,
'value' => $value,
);
}
echo json_encode($ret);
return false;
}
protected function delete_id_handler()
{
// forcing sequential requests here
$_SESSION['appendingOrder'] = true;
list($upc, $store, $vendor) = explode(',', $this->id);
$findP = $this->connection->prepare("SELECT orderID
FROM PurchaseOrder WHERE placed=0 AND storeID=? AND vendorID=? AND userID=-99");
$orderID = $this->connection->getValue($findP, array($store, $vendor));
$delP = $this->connection->prepare("DELETE FROM PurchaseOrderItems
WHERE orderID=? AND internalUPC=?");
$this->connection->execute($delP, array($orderID, $upc));
echo json_encode(array('unlink' => false));
return false;
}
protected function post_id_handler()
{
// forcing sequential requests here
$_SESSION['appendingOrder'] = true;
list($upc, $store, $vendor) = explode(',', $this->id);
$findP = $this->connection->prepare("SELECT orderID
FROM PurchaseOrder WHERE placed=0 AND storeID=? AND vendorID=? AND userID=-99");
$orderID = $this->connection->getValue($findP, array($store, $vendor));
if (!$orderID) {
$model = new PurchaseOrderModel($this->connection);
$model->storeID($store);
$model->vendorID($vendor);
$model->creationDate(date('Y-m-d H:i:s'));
$model->userID(-99);
$orderID = $model->save();
}
$itemP = $this->connection->prepare("SELECT * FROM RpOrderItems WHERE upc=? AND storeID=?");
$item = $this->connection->getRow($itemP, array($upc, $store));
if ($item === false) {
$this->logger->debug("No item for UPC {$upc}, store {$store}");
}
if (substr($upc, 0, 2) == "LC") {
$prodP = $this->connection->prepare("SELECT p.brand, p.size, p.cost FROM upcLike AS u
INNER JOIN products AS p ON u.upc=p.upc WHERE u.likeCode=?");
$prod = $this->connection->getRow($prodP, array(substr($upc, 2)));
} else {
$prodP = $this->connection->prepare("SELECT brand, size, cost FROM products WHERE upc=?");
$prod = $this->connection->getRow($prodP, array($upc));
}
$mapP = $this->connection->prepare("SELECT sku FROM RpFixedMaps WHERE likeCode=?");
$mapped = $this->connection->getValue($mapP, array(str_replace('LC', '', $upc)));
if ($mapped) {
$item['vendorSKU'] = $mapped;
}
if (!$item['vendorSKU']) {
$item['vendorSKU'] = $upc;
}
if (!$item['backupSKU']) {
$item['backupSKU'] = $upc;
}
$sku = $vendor == $item['backupID'] ? $item['backupSKU'] : $item['vendorSKU'];
if ($item['caseSize'] != 0) {
$prod['cost'] = $item['cost'] / $item['caseSize'];
} else {
$prod['cost'] = $item['cost'];
}
if ($sku == 'DIRECT') {
$sku = $upc;
}
$poi = new PurchaseOrderItemsModel($this->connection);
$poi->orderID($orderID);
$poi->sku($sku);
$poi->quantity(FormLib::get('qty'));
$poi->unitCost($prod['cost']);
$poi->caseSize($item['caseSize']);
$poi->unitSize($prod['size']);
$poi->brand($prod['brand']);
$poi->description($vendor == $item['backupID'] ? $item['backupItem'] : $item['vendorItem']);
$poi->internalUPC($upc);
$poi->save();
$vendP = $this->connection->prepare("SELECT vendorName FROM vendors WHERE vendorID=?");
$vend = $this->connection->getValue($vendP, array($vendor));
echo json_encode(array('orderID' => $orderID, 'name'=>$vend));
$_SESSION['appendingOrder'] = false;
return false;
}
protected function post_view()
{
$model = new RpOrderItemsModel($this->connection);
$model->storeID(FormLib::get('store'));
$model->categoryID(FormLib::get('catID'));
$model->addedBy(1);
$model->caseSize(FormLib::get('caseSize'));
$model->vendorID(FormLib::get('vendor'));
$model->vendorSKU(FormLib::get('sku'));
$model->vendorItem(FormLib::get('item'));
$model->cost(FormLib::get('cost'));
$model->backupID(0);
$lc = FormLib::get('lc');
$upc = BarcodeLib::padUPC(FormLib::get('upc'));
if ($lc) {
$model->upc('LC' . $lc);
} elseif ($upc != '0000000000000') {
$model->upc($upc);
} elseif (FormLib::get('sku')) {
$model->upc(FormLib::get('sku'));
} else {
$model->upc(uniqid());
}
$saved = $model->save();
$ret = '';
if ($saved) {
$ret .= '<div class="alert alert-success">Added item</div>';
} else {
$ret .= '<div class="alert alert-danger">Error adding item</div>';
}
return $ret . $this->get_view();
}
protected function isMobile()
{
$userAgent = strtolower(filter_input(INPUT_SERVER, 'HTTP_USER_AGENT'));
if (strstr($userAgent, 'android')) {
return true;
} elseif (strstr($userAgent, 'iphone os')) {
return true;
}
return false;
}
protected function get_view()
{
$this->addScript('rpOrder.js?date=20210224');
$this->addOnloadCommand('rpOrder.initAutoCompletes();');
$store = FormLib::get('store');
if (!$store) {
$store = COREPOS\Fannie\API\lib\Store::getIdByIp();
}
$sSelect = FormLib::storePicker();
$sSelect['html'] = str_replace('<select', '<select onchange="location=\'RpOrderPage.php?store=\' + this.value;"', $sSelect['html']);
$jsState = isset($_SESSION['rpState']) ? json_encode($_SESSION['rpState']) : "false";
if ($jsState === "false") {
$sModel = new RpSessionsModel($this->connection);
$sModel->dataType('RP');
$sModel->userID($this->userID);
if ($sModel->load()) {
$jsState = $sModel->data();
$_SESSION['rpState'] = json_decode($sModel->data(), true);
}
}
$this->addOnloadCommand("rpOrder.initState({$jsState});");
$fieldType = $this->isMobile() ? 'type="number" min="0" max="99999" step="0.01"' : 'type="text"';
$ordersP = $this->connection->prepare("
SELECT o.orderID, v.vendorName
FROM PurchaseOrder AS o
LEFT JOIN vendors AS v ON o.vendorID=v.vendorID
WHERE o.storeID=?
AND o.placed=0
AND o.userID=-99");
$orderLinks = '';
$orderIDs = array();
$orders = $this->connection->getAllRows($ordersP, array($store));
foreach ($orders as $o) {
$orderIDs[] = $o['orderID'];
$orderLinks .= sprintf('<li id="link%d"><a href="../../../purchasing/ViewPurchaseOrders.php?id=%d">%s</a></li>',
$o['orderID'], $o['orderID'], $o['vendorName']);
}
$printLink = '';
if (count($orderIDs) > 0) {
$printLink = '<a href="RpPrintOrders.php?id=' . implode(',', $orderIDs) . '">Print these</a>';
}
list($ioStr, $ioArgs) = $this->connection->safeInClause($orderIDs);
$inOrderP = $this->connection->prepare("SELECT vendorID, quantity FROM PurchaseOrder AS o
INNER JOIN PurchaseOrderItems AS i ON o.orderID=i.orderID
WHERE o.orderID IN ({$ioStr}) AND i.internalUPC=?");
$parP = $this->connection->prepare("
SELECT movement
FROM " . FannieDB::fqn('Smoothed', 'plugin:WarehouseDatabase') . "
WHERE storeID=?
AND upc=?");
$priceP = $this->connection->prepare("
SELECT CASE WHEN p.special_price > 0 THEN p.special_price ELSE p.normal_price END AS price
FROM upcLike AS u
INNER JOIN products AS p ON p.upc=u.upc
WHERE u.likeCode=?");
$costP = $this->connection->prepare("SELECT cost, units FROM vendorItems WHERE vendorID=? and sku=?");
$mapR = $this->connection->query("SELECT * FROM RpFixedMaps AS r LEFT JOIN vendorItems AS v ON r.sku=v.sku AND r.vendorID=v.vendorID");
$mappings = array();
while ($mapW = $this->connection->fetchRow($mapR)) {
$mappings[$mapW['likeCode']] = $mapW;
}
$lcR = $this->connection->query("SELECT likeCode, likeCodeDesc, organic FROM likeCodes WHERE likeCode < 1000");
$lcInfo = array();
while ($lcW = $this->connection->fetchRow($lcR)) {
$lcInfo[$lcW['likeCode']] = $lcW;
}
$dow = date('N');
$saleDate = date('Y-m-d');
if ($dow >= 6 || $dow <= 2) {
$ts = time();
while (date('N', $ts) != 3) {
$ts = mktime(0, 0, 0, date('n',$ts), date('j',$ts) + 1, date('Y',$ts));
}
$saleDate = date('Y-m-d', $ts);
}
$saleP = $this->connection->prepare("SELECT endDate
FROM batchList AS l
INNER JOIN batches AS b ON l.batchID=b.batchID
INNER JOIN StoreBatchMap AS m ON l.batchID=m.batchID
WHERE l.upc=? AND m.storeID=?
AND '{$saleDate}' BETWEEN startDate AND endDate
AND b.discountType > 0");
$ago = date('Y-m-d', strtotime('-3 days'));
$ahead = date('Y-m-d', strtotime('+3 days'));
$startingP = $this->connection->prepare("SELECT startDate
FROM batchList AS l
INNER JOIN batches AS b ON l.batchID=b.batchID
INNER JOIN StoreBatchMap AS m ON l.batchID=m.batchID
WHERE l.upc=? AND m.storeID=?
AND b.startDate BETWEEN '{$ago}' AND '{$ahead}'
AND b.discountType > 0");
$endingP = $this->connection->prepare("SELECT endDate
FROM batchList AS l
INNER JOIN batches AS b ON l.batchID=b.batchID
INNER JOIN StoreBatchMap AS m ON l.batchID=m.batchID
WHERE l.upc=? AND m.storeID=?
AND b.endDate BETWEEN '{$ago}' AND '{$ahead}'
AND b.discountType > 0");
$prep = $this->connection->prepare("
SELECT r.upc,
r.categoryID,
c.name,
v.vendorName AS vendorName,
b.vendorName AS backupVendor,
r.vendorSKU,
r.vendorItem,
r.backupSKU,
r.backupItem,
r.caseSize,
r.vendorID,
r.backupID,
r.cost
FROM RpOrderItems AS r
LEFT JOIN RpOrderCategories AS c ON r.categoryID=c.rpOrderCategoryID
LEFT JOIN vendors AS v ON r.vendorID=v.vendorID
LEFT JOIN vendors AS b ON r.backupID=b.vendorID
WHERE r.storeID=?
AND r.deleted=0
ORDER BY c.seq, c.name, r.vendorItem");
$res = $this->connection->execute($prep, array($store));
$tables = '';
$category = false;
while ($row = $this->connection->fetchRow($res)) {
if ($row['categoryID'] !== $category) {
if ($category !== false) {
$tables .= '</table>';
}
$catName = $row['categoryID'] ? $row['name'] : 'Uncategorized';
$tables .= '<h3>' . $catName . '</h3>';
$category = $row['categoryID'];
$tables .= '<table class="table table-bordered table-striped small">
<tr><th>LC</th><th>Primary</th><th>Secondary</th><th>Item</th><th>Case Size</th>
<th>On Hand</th><th>Par</th><th>Order</th></tr>';
}
$lc = str_replace('LC', '', $row['upc']);
$mapped = isset($mappings[$lc]) ? $mappings[$lc] : false;
if ($mapped) {
$row['vendorSKU'] = $mapped['sku'];
$row['lookupID'] = $mapped['vendorID'];
if ($mapped['description']) {
$row['vendorItem'] = $mapped['description'];
}
}
$lcRow = isset($lcInfo[$lc]) ? $lcInfo[$lc] : array('likeCodeDesc'=>'', 'organic'=>false);
$lcName = $lcRow['likeCodeDesc'];
$organic = $lcRow['organic'] ? true : false;
$par = $this->connection->getValue($parP, array($store, $row['upc']));
if ($row['caseSize'] != 0 && ($par / $row['caseSize']) < 0.1) {
$par = 0.1 * $row['caseSize'];
if ($store == 2) {
$par = 0.05 * $row['caseSize'];
}
}
$price = $this->connection->getValue($priceP, array(substr($row['upc'], 2)));
$cost = array('cost' => $row['cost'], 'units' => $row['caseSize']);
if ($row['caseSize'] != 0) {
$cost['cost'] = $cost['cost'] / $row['caseSize'];
}
$onSale = $this->connection->getValue($saleP, array($row['upc'], $store));
$startIcon = '';
$starting = $this->connection->getValue($startingP, array($row['upc'], $store));
if ($starting) {
$startIcon = sprintf('<span class="glyphicon glyphicon-arrow-up" title="%s" />',
'Sale ' . ($onSale ? 'started' : 'starting') . ' on ' . $starting);
}
$endIcon = '';
$ending = $this->connection->getValue($endingP, array($row['upc'], $store));
if ($ending) {
$endIcon = sprintf('<span class="glyphicon glyphicon-arrow-down" title="%s" />',
'Sale ' . ($onSale ? 'ending' : 'ended') . ' on ' . $ending);
}
$upc = $row['upc'];
if (substr($row['upc'], 0, 2) == 'LC') {
$row['upc'] = sprintf('<a href="../../../item/likecodes/LikeCodeEditor.php?start=%d">%s</a>',
substr($row['upc'], 2), $row['upc']);
}
$orderAmt = '';
/* don't do naive, pre-inventory suggested amounts
$start = $par;
while ($start > (0.25 * $row['caseSize'])) {
$orderAmt++;
$start -= $row['caseSize'];
if ($orderAmt > 100) {
echo $row['upc'] . ": $par, {$row['caseSize']}<br />";
break;
}
}
*/
$inOrder = $this->connection->getRow($inOrderP, array_merge($ioArgs, array(substr($upc, 0, 13))));
if ($inOrder) {
$orderAmt = $inOrder['quantity'];
}
$row['vendorName'] = str_replace(' (Produce)', '', $row['vendorName']);
$row['backupVendor'] = str_replace(' (Produce)', '', $row['backupVendor']);
$highlight = '';
$tooltip = '';
if ($onSale) {
$highlight = 'rp-success';
$tooltip = "On sale through {$onSale}";
} elseif (!$organic) {
$highlight = 'alert-warning';
$tooltip = 'Conventional';
}
$tables .= sprintf('<tr class="item-row vendor-%d">
<td class="upc %s">%s %s</td>
<td class="%s">%s</td>
<td class="%s">%s</td>
<td class="%s" title="%s">$%.2f %s %s %s%s</td>
<td class="caseSize">%s</td>
<td><input %s class="form-control input-sm onHand" value=""
style="width: 5em;" id="onHand%s" data-incoming="0"
onchange="rpOrder.reCalcRow($(this).closest(\'tr\')); rpOrder.updateOnHand(this);"
onfocus="this.select();" onkeyup="rpOrder.onHandKey(event);" />
<span class="incoming-notice"></span></td>
<input type="hidden" class="price" value="%.2f" />
<input type="hidden" class="basePar" value="%.2f" />
<td class="parCell">%.2f</td>
<td class="form-inline %s">
<input %s style="width: 5em;"class="form-control input-sm orderAmt"
id="orderAmt%s" onkeyup="rpOrder.orderKey(event); rpOrder.updateOrder(this);"
onfocus="this.select();" value="%s" />
<button class="btn btn-success btn-sm" onclick="rpOrder.inc(this, 1);">+</button>
<button class="btn btn-danger btn-sm" onclick="rpOrder.inc(this, -1);">-</button>
<label><input type="checkbox" class="orderPri" onchange="rpOrder.placeOrder(this);" value="%s,%d,%d" %s /> Pri</label>
<label><input type="checkbox" class="orderSec" onchange="rpOrder.placeOrder(this);" value="%s,%d,%d" %s %s /> Sec</label>
</td>
</tr>',
$row['vendorID'],
$highlight, $row['upc'], $lcName,
$highlight,
$row['vendorName'],
$highlight,
$row['backupVendor'],
$highlight,
$tooltip,
($cost ? $cost['cost'] : 0) * $row['caseSize'],
($row['vendorSKU'] ? '(' . $row['vendorSKU'] . ')' : ''),
$row['vendorItem'],
$startIcon, $endIcon,
$row['caseSize'],
$fieldType,
$upc,
$price,
$par,
($row['caseSize'] != 0 ? $par / $row['caseSize'] : 0),
($inOrder ? 'info' : ''),
$fieldType,
$upc,
$orderAmt,
$upc, $store, $row['vendorID'],
($inOrder && $inOrder['vendorID'] == $row['vendorID'] ? 'checked' : ''),
$upc, $store, $row['backupID'],
($inOrder && $inOrder['vendorID'] == $row['backupID'] ? 'checked' : ''),
($row['backupID'] ? '' : 'disabled')
);
}
$tables .= '</table>';
$ts = time();
while (date('N', $ts) != 1) {
$ts = mktime(0, 0, 0, date('n', $ts), date('j',$ts) - 1, date('Y', $ts));
}
$weekStart = date('Y-m-d', $ts);
$weekP = $this->connection->prepare("SELECT * FROM RpSegments WHERE startDate=? AND storeID=?");
$nextWeekStart = date('Y-m-d', mktime(0, 0, 0, date('n', $ts), date('j', $ts) + 7, date('Y', $ts)));
$projected = 'n/a';
$baseRetain = 60;
$days = array(
'Mon' => 'n/a',
'Tue' => 'n/a',
'Wed' => 'n/a',
'Thu' => 'n/a',
'Fri' => 'n/a',
'Sat' => 'n/a',
'Sun' => 'n/a',
);
$week = $this->connection->getRow($weekP, array($weekStart, $store));
$nextWeek = $this->connection->getRow($weekP, array($nextWeekStart, $store));
$modProj = 0;
if ($week) {
$projected = number_format($week['sales']);
$baseRetain = $week['retention'];
$days = json_decode($week['segmentation'], true);
$days = array_map(function ($i) { return sprintf('%.2f%%', $i*100); }, $days);
$thisYear = json_decode($week['thisYear'], true);
$thisYear = is_array($thisYear) ? $thisYear : array();
$lastYear = json_decode($week['lastYear'], true);
$sums = array('this' => 0, 'last' => 0, 'proj' => 0);
$dataPoints = 0;
foreach ($thisYear as $key => $val) {
if ($val > 0 && $lastYear[$key] > 0) {
$sums['this'] += $val;
$sums['last'] += $lastYear[$key];
$sums['proj'] += str_replace(',', '', $projected) * (str_replace('%', '', $days[$key]) / 100.00);
$dataPoints++;
}
}
if ($dataPoints > 0) {
$growth = ($sums['this'] - $sums['proj']) / $sums['proj'];
$growth *= ($dataPoints / 7);
foreach ($days as $day) {
$val = str_replace(',', '', $projected) * (str_replace('%', '', $day) / 100.00);
$modProj += ($val * (1 + $growth));
}
/*
foreach ($lastYear as $key => $val) {
$modProj += ($val * (1 + $growth));
}
*/
$modProj = round($modProj, 2);
}
}
if ($nextWeek && (date('N') == 6 || date('N') == 7)) {
$nextWeekDays = json_decode($nextWeek['segmentation'], true);
$mondayTarget = $nextWeek['sales'] * $nextWeekDays['Mon'];
$mondayShare = $mondayTarget / $week['sales'];
$days['Mon'] = sprintf('%.2f%%', $mondayShare * 100);
}
$mStamp = date('N') == 1 ? strtotime('today') : strtotime('last monday');
$dateIDs = array();
for ($i=0; $i<7; $i++) {
$dateIDs[] = date('Ymd', mktime(0,0,0,date('n',$mStamp),date('j',$mStamp)+$i,date('Y',$mStamp)));
}
$cats = new RpOrderCategoriesModel($this->connection);
$catOpts = $cats->toOptions();
return <<<HTML
<div class="row">
<div class="col-sm-6">
<p class="form-inline">
<label>Store</label>: {$sSelect['html']}
<label>Projected Sales this Week</label>:
<a href="RpSegmentation.php" id="projSales">{$projected}</a>
|
<a href="RpFileManager.php">RP Data</a>
<fieldset>
<label title="{$days['Mon']}"><input type="checkbox" class="daycheck"
data-dateid="{$dateIDs[0]}"
onchange="rpOrder.updateDays();" value="{$days['Mon']}" /> Monday</label>
<label title="{$days['Tue']}"><input type="checkbox" class="daycheck"
data-dateid="{$dateIDs[1]}"
onchange="rpOrder.updateDays();" value="{$days['Tue']}" /> Tuesday</label>
<label title="{$days['Wed']}"><input type="checkbox" class="daycheck"
data-dateid="{$dateIDs[2]}"
onchange="rpOrder.updateDays();" value="{$days['Wed']}" /> Wednesday</label>
<label title="{$days['Thu']}"><input type="checkbox" class="daycheck"
data-dateid="{$dateIDs[3]}"
onchange="rpOrder.updateDays();" value="{$days['Thu']}" /> Thursday</label>
<label title="{$days['Fri']}"><input type="checkbox" class="daycheck"
data-dateid="{$dateIDs[4]}"
onchange="rpOrder.updateDays();" value="{$days['Fri']}" /> Friday</label>
<label title="{$days['Sat']}"><input type="checkbox" class="daycheck"
data-dateid="{$dateIDs[5]}"
onchange="rpOrder.updateDays();" value="{$days['Sat']}" /> Saturday</label>
<label title="{$days['Sun']}"><input type="checkbox" class="daycheck"
data-dateid="{$dateIDs[6]}"
onchange="rpOrder.updateDays();" value="{$days['Sun']}" /> Sunday</label>
</fieldset>
<label title="Based on sales growth so far this week">Modified Projection</label>:
<span id="modProj">{$modProj}</span>
<br />
<label>Projected Sales these Days</label>:
<span id="selectedSales">0</span>
<br />
<label>Retail x Expected Movement</label>:
<span id="guessRetail">0</span>
<br />
<label>Adjustment</label>:
<span id="adjDiff">0</span>
<div class="form-inline">
<div class="input-group">
<span class="input-group-addon">Retention</span>
<input type="number" disabled value="{$baseRetain}" id="retention" class="form-control input-sm" />
<span class="input-group-addon">%</span>
</div>
</div>
<p>
<ul id="openOrders">{$orderLinks}</ul>
<span id="printLink">{$printLink}</span>
</p>
</p>
</div>
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">Add Item</div>
<div class="panel-body">
<form method="post">
<input type="hidden" name="store" value="{$store}" />
<div class="form-group input-group">
<span class="input-group-addon">Vendor</span>
<select name="vendor" class="form-control input-sm" required
id="newVendor" onchange="rpOrder.setSearchVendor(this.value);">
<option value=""></option>
<option value="292">Alberts</option>
<option value="293">CPW</option>
<option value="136">RDW</option>
<option value="358">KeHE</option>
<option value="1">UNFI</option>
<option value="-2">Direct</option>
</select>
</div>
<div class="form-group input-group">
<span class="input-group-addon">Item</span>
<input type="text" class="form-control input-sm" name="item" required id="newItem" />
</div>
<div class="col-sm-6">
<div class="form-group input-group">
<span class="input-group-addon">Likecode</span>
<input type="text" class="form-control input-sm" name="lc" id="newLC" />
</div>
</div>
<div class="col-sm-6">
<div class="form-group input-group">
<span class="input-group-addon">or UPC</span>
<input type="text" class="form-control input-sm" name="upc" id="newUPC" />
</div>
</div>
<div class="col-sm-4">
<div class="form-group input-group">
<span class="input-group-addon">SKU</span>
<input type="text" class="form-control input-sm" name="sku" id="newSKU" />
</div>
</div>
<div class="col-sm-4">
<div class="form-group input-group">
<span class="input-group-addon">Case Size</span>
<input type="text" class="form-control input-sm" name="caseSize" required id="newCase" value="1" />
</div>
</div>
<div class="col-sm-4">
<div class="form-group input-group">
<span class="input-group-addon">Case Cost</span>
<input type="text" class="form-control input-sm" name="cost" required id="newCost" />
</div>
</div>
<div class="form-group input-group">
<span class="input-group-addon">Category</span>
<select name="catID" class="form-control input-sm" required>{$catOpts}</select>
</div>
<button type="submit" class="btn btn-default">Add Item</button>
<button type="reset" class="btn btn-default btn-reset">Clear</button>
</form>
</div>
</div>
</div>
</div>
<p>
<button class="btn btn-default orderAll" onclick="rpOrder.orderAll();">Order All</button>
<a href="RpDirectPage.php" class="btn btn-default">Switch to Direct</a>
<a href="" class="btn btn-success" onclick="rpOrder.save(); return false;">Save</a>
<span class="last-save">n/a</span>
<div class="form-inline">
<strong>Filter</strong>
<label><input class="vFilter" type="checkbox" checked value="292" onchange="rpOrder.vendorFilter();" /> Alberts</label>
<label><input class="vFilter" type="checkbox" checked value="293" onchange="rpOrder.vendorFilter();" /> CPW</label>
<label><input class="vFilter" type="checkbox" checked value="136" onchange="rpOrder.vendorFilter();" /> RDW</label>
<label><input class="vFilter" type="checkbox" checked value="-2" onchange="rpOrder.vendorFilter();" /> Direct</label>
</div>
<div class="form-group">
<label>
<input type="checkbox" checked id="autoOrderCheck" />
Auto-fill order amounts
</label>
</div>
<div class="progress collapse">
<div class="progress-bar progress-bar-striped active" role="progressbar"
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%">
<span class="sr-only">Ordering</span>
</div>
</div>
</p>
{$tables}
<p>
<button class="btn btn-default orderAll" onclick="rpOrder.orderAll();">Order All</button>
<a href="RpDirectPage.php" class="btn btn-default">Switch to Direct</a>
<a href="" class="btn btn-success" onclick="rpOrder.save(); return false;">Save</a>
<span class="last-save">n/a</span>
<div class="progress collapse">
<div class="progress-bar progress-bar-striped active" role="progressbar"
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%">
<span class="sr-only">Searching</span>
</div>
</div>
</p>
<p>
<ul id="altOpenOrders">{$orderLinks}</ul>
<span id="altPrintLink">{$printLink}</span>
</p>
<hr />
<p>
<a href="RpOrderPage.php?clear=1" class="btn btn-danger">Clear My Session</a>
</p>
<div id="eruda">
</div>
<script src="//cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init({ container: document.getElementById('eruda') });</script>
HTML;
}
protected function css_content()
{
return <<<CSS
.rp-success {
background-color: #f772d2;
}
.table-striped>tbody>tr:nth-child(odd)>td.rp-success {
background-color: #f772d2;
}
.incoming-notice {
font-weight: bold;
color: #15AF23;
}
CSS;
}
}
FannieDispatch::conditionalExec();