fannie/item/vendors/VendorIndexPage.php
<?php
/*******************************************************************************
Copyright 2009,2013 Whole Foods Co-op
This file is part of CORE-POS.
CORE-POS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
CORE-POS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
in the file license.txt along with IT CORE; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*********************************************************************************/
/* --COMMENTS - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
12Mar2013 Andy Theuninck Use API classes
7Sep2012 Eric Lee Display vendorID in select.
Display both "Select" and "New" options.
*/
include(dirname(__FILE__) . '/../../config.php');
if (!class_exists('FannieAPI')) {
include(__DIR__ . '/../../classlib2.0/FannieAPI.php');
}
class VendorIndexPage extends FannieRESTfulPage
{
protected $title = "Fannie : Manage Vendors";
protected $header = "Manage Vendors";
protected $must_authenticate = true;
//protected $auth_classes = array('pricechange');
private $canEdit = false;
public $description = '[Vendor Editor] creates or update information about vendors.';
public function preprocess()
{
$this->addRoute(
'get<id><autoAdd>',
'post<new><name>',
'get<info>',
'post<info>',
'post<delivery>',
'post<id><shipping>',
'post<id><rate>',
'post<id><inactive>',
'post<id><autoID>'
);
$this->canEdit = FannieAuth::validateUserQuiet('pricechange');
return parent::preprocess();
}
protected function post_id_autoID_handler()
{
if (!$this->canEdit) return false;
$dbc = $this->connection;
$dbc->selectDB($this->config->get('OP_DB'));
$map = new AutoOrderMapModel($dbc);
$map->vendorID($this->id);
$enables = FormLib::get('autoEnable', array());
$accounts = FormLib::get('autoAccount', array());
for ($i=0; $i<count($this->autoID); $i++) {
$map->storeID($this->autoID[$i]);
$active = in_array($map->storeID(), $enables);
$map->active($active ? 1 : 0);
$map->accountID($accounts[$i]);
$map->save();
}
$vendor = new VendorsModel($dbc);
$vendor->vendorID($this->id);
$vendor->orderMinimum(FormLib::get('minOrder', 0));
$vendor->halfCases(FormLib::get('halfs', false) ? 1 : 0);
$vendor->save();
return false;
}
protected function get_id_autoAdd_handler()
{
$this->autoPopulate($this->id);
return 'VendorIndexPage.php?vid=' . $this->id;
}
protected function post_new_name_handler()
{
if (!$this->canEdit) return false;
echo $this->newVendor($this->name);
return false;
}
protected function get_info_handler()
{
$this->getVendorInfo(FormLib::get('vid',0));
return false;
}
protected function post_info_handler()
{
if (!$this->canEdit) return false;
$id = FormLib::get('vendorID','');
if ($id === '') {
echo json_encode(array('error'=>1, 'msg'=>'Bad request'));
return false;
}
$web = FormLib::get('website');
if (!empty($web) && substr(strtolower($web),0,4) !== "http") {
$web = 'http://'.$web;
}
$localID = FormLib::get('local-origin-id', 0);
$dbc = FannieDB::get($this->config->get('OP_DB'));
$vModel = new VendorsModel($dbc);
$vModel->vendorID($id);
$vModel->phone(FormLib::get('phone'));
$vModel->fax(FormLib::get('fax'));
$vModel->email(trim(FormLib::get('email')));
$vModel->website($web);
$vModel->notes(FormLib::get('notes'));
$vModel->address(FormLib::get('address'));
$vModel->city(FormLib::get('city'));
$vModel->state(FormLib::get('state'));
$vModel->zip(FormLib::get('zip'));
$vModel->localOriginID($localID);
$success = $vModel->save();
$ret = array('error'=>0, 'msg'=>'');
if ($success) {
$ret['msg'] = 'Saved vendor information';
} else {
$ret['msg'] = 'Error saving vendor information';
$ret['error'] = 1;
}
echo json_encode($ret);
return false;
}
protected function post_id_inactive_handler()
{
if (!$this->canEdit) return false;
$dbc = $this->connection;
$dbc->setDefaultDB($this->config->OP_DB);
$vModel = new VendorsModel($dbc);
$vModel->vendorID($this->id);
$vModel->inactive($this->inactive);
$vModel->save();
return false;
}
protected function post_id_shipping_handler()
{
if (!$this->canEdit) return false;
$ret = array('error'=>0);
if ($this->id === ''){
$ret['error'] = 'Bad request';
} else {
$dbc = FannieDB::get($this->config->get('OP_DB'));
$vModel = new VendorsModel($dbc);
$vModel->vendorID($this->id);
$vModel->shippingMarkup($this->shipping / 100.00);
if (!$vModel->save()) {
$ret['error'] = 'Save failed!';
}
}
echo json_encode($ret);
return false;
}
protected function post_id_rate_handler()
{
if (!$this->canEdit) return false;
$ret = array('error'=>0);
if ($this->id === ''){
$ret['error'] = 'Bad request';
} else {
$dbc = $this->connection;
$dbc->setDefaultDB($this->config->OP_DB);
$vModel = new VendorsModel($dbc);
$vModel->vendorID($this->id);
$vModel->discountRate($this->rate / 100.00);
if (!$vModel->save()) {
$ret['error'] = 'Save failed!';
}
}
echo json_encode($ret);
return false;
}
protected function post_delivery_handler()
{
if (!$this->canEdit) return false;
$delivery = new VendorDeliveriesModel(FannieDB::get($this->config->get('OP_DB')));
$delivery->vendorID(FormLib::get('vID', 0));
$delivery->frequency(FormLib::get('frequency', 'weekly'));
$delivery->regular( FormLib::get('regular') ? 1 : 0 );
$delivery->sunday( FormLib::get('sunday') ? 1 : 0 );
$delivery->monday( FormLib::get('monday') ? 1 : 0 );
$delivery->tuesday( FormLib::get('tuesday') ? 1 : 0 );
$delivery->wednesday( FormLib::get('wednesday') ? 1 : 0 );
$delivery->thursday( FormLib::get('thursday') ? 1 : 0 );
$delivery->friday( FormLib::get('friday') ? 1 : 0 );
$delivery->saturday( FormLib::get('saturday') ? 1 : 0 );
$ret = array();
if ($delivery->regular()) {
$delivery->autoNext();
$ts1 = strtotime($delivery->nextDelivery());
$ts2 = strtotime($delivery->nextNextDelivery());
if ($ts1 !== false && $ts2 !== false) {
$ret['next'] = date('D, M jS', $ts1);
$ret['nextNext'] = date('D, M jS', $ts2);
}
}
$delivery->save();
echo json_encode($ret);
return false;
}
private function autoPopulate($vendorID)
{
if (!$this->canEdit) return false;
$dbc = FannieDB::get($this->config->get('OP_DB'));
$query = '
SELECT p.upc,
p.upc AS sku,
p.brand,
p.description,
p.size,
p.unitofmeasure,
p.cost,
0.00 AS saleCost,
0 AS vendorDept
FROM products AS p
INNER JOIN vendors AS v ON p.default_vendor_id=v.vendorID
WHERE v.vendorID=?
AND p.upc NOT IN (
SELECT upc FROM vendorItems WHERE vendorID=?
) AND p.upc NOT IN (
SELECT upc FROM VendorAliases WHERE vendorID=?
)';
$prep = $dbc->prepare($query);
$args = array($vendorID, $vendorID, $vendorID);
$result = $dbc->execute($prep, $args);
$item = new VendorItemsModel($dbc);
while ($row = $dbc->fetch_row($result)) {
$item->vendorID($vendorID);
$item->upc($row['upc']);
$item->sku($row['sku']);
$item->brand($row['brand']);
$item->description($row['description']);
$item->units(1);
$item->size($row['size'] . $row['unitofmeasure']);
$item->cost($row['cost']);
$item->saleCost(0);
$item->vendorDept(0);
$item->save();
}
}
private function getVendorInfo($id)
{
$dbc = FannieDB::get($this->config->get('OP_DB'));
$ret = "";
$noEdit = !$this->canEdit ? 'disabled' : '';
$noShow = !$this->canEdit ? 'collapse' : '';
$model = new VendorsModel($dbc);
$model->vendorID($id);
$model->load();
$ret .= '<div>';
$ret .= "<b>Id</b>: $id <b>Name</b>: " . $model->vendorName();
$ret .= ' <label>Active
<input type="checkbox" onchange="vendorEditor.toggleActive(this, ' . $id . ')" '
. ($model->inactive() == 1 ? '' : 'checked') . ' ' . $noEdit . ' />
</label>';
$ret .= sprintf(' | <a class="%s" href="RenameVendorPage.php?id=%d">Rename %s</a>', $noShow, $id, $model->vendorName());
$ret .= sprintf(' | <a class="%s" href="DeleteVendorPage.php?id=%d">Delete %s</a>', $noShow, $id, $model->vendorName());
$ret .= '</div>';
$itemQ = $dbc->prepare("SELECT COUNT(*) FROM vendorItems WHERE vendorID=?");
$itemR = $dbc->execute($itemQ,array($id));
$num = 0;
if ($itemR && $row = $dbc->fetch_row($itemR)) {
$num = $row[0];
}
$ret .= '
<div class="row">
<div class="container-fluid col-sm-3">';
$ret .= '
<div class="panel panel-default">
<div class="panel-heading">Catalog</div>
<div class="panel-body">
This vendor contains ' . $num . ' items<br />';
if ($num > 0) {
$ret .= "<a class=\"{$noShow}\" href=\"BrowseVendorItems.php?vid=$id\">Browse vendor catalog</a>";
if ($num <= 750) {
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"EditVendorItems.php?id=$id\">Edit vendor catalog</a>";
}
}
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"UpdateUploadPage.php?vid=$id\">Upload & Update vendor catalog</a>";
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"DefaultUploadPage.php?vid=$id\">Upload & Replace vendor catalog</a>";
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"VendorIndexPage.php?id=$id&autoAdd=1\">Add existing items to catalog</a>";
$ret .= '</div></div>';
$ret .= '</div><div class="container-fluid col-sm-3">';
$ret .= '
<div class="panel panel-default">
<div class="panel-heading">Mappings</div>
<div class="panel-body">';
$ret .= "<a class=\"{$noShow}\" href=\"VendorAliasesPage.php?id=$id\">Manage Aliases</a>";
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"UploadPluMapPage.php?vid=$id\">Upload PLU/SKU mapping</a>";
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"SkuMapPage.php?id=$id\">View or Edit PLU/SKU mapping</a>";
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"UnitBreakdownPage.php?id=$id\">View or Edit Breakdown mapping</a>";
$ret .= '</div></div>';
$ret .= '</div><div class="container-fluid col-sm-3">';
$ret .= '
<div class="panel panel-default">
<div class="panel-heading">Margin</div>
<div class="panel-body">';
$itemQ = $dbc->prepare("SELECT COUNT(*) FROM vendorDepartments WHERE vendorID=?");
$itemR = $dbc->execute($itemQ,array($id));
$num = 0;
if ($itemR && $row = $dbc->fetch_row($itemR)) {
$num = $row[0];
}
$ret .= '<p>';
$ret .= "<a href=\"../../batches/UNFI/\">Vendor Price Batch Tools</a>";
$ret .= "</p><p>";
if ($num == 0) {
$ret .= "<a class=\"{$noShow}\" href=\"VendorDepartmentEditor.php?vid=$id\">This vendor's items are not yet arranged into subcategories</a>";
$ret .= '<p />';
$ret .= "<a class=\"{$noShow}\" href=\"VendorDepartmentUploadPage.php?vid=$id\">Upload Subcategory List</a>";
} else {
$ret .= "This vendor's items are divided into ";
$ret .= $num." subcategories";
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"VendorDepartmentEditor.php?vid=$id\">View or Edit vendor subcategory margin(s)</a>";
$ret .= "<br />";
$ret .= "<a class=\"{$noShow}\" href=\"VendorMarginsPage.php?id=$id\">View or Edit vendor-specific POS department margins</a>";
$ret .= '<p />';
$ret .= "<a class=\"{$noShow}\" href=\"VendorDepartmentUploadPage.php?vid=$id\">Upload Subcategory List</a>";
}
$ret .= '</p>';
$ret .= '
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">Shipping</span>
<input type="text" id="vc-shipping" name="shipping" ' . $noEdit . '
onchange="vendorEditor.saveShipping(this.value);"
title="Markup percentage to account for shipping fees"
class="form-control" value="' . $model->shippingMarkup() * 100 . '" />
<span class="input-group-addon">%</span>
</div>
</div>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">Discount Rate</span>
<input type="text" id="vc-discount" name="discount-rate" ' . $noEdit . '
title="Markdown percentage from catalog list costs"
onchange="vendorEditor.saveDiscountRate(this.value);"
class="form-control" value="' . $model->discountRate() * 100 . '" />
<span class="input-group-addon">%</span>
</div>
</div>';
$ret .= '</div></div>';
$ret .= '</div></div>';
$ret .= '
<div class="panel panel-default">
<div class="panel-heading">Contact Info</div>
<div class="panel-body">
<div class="form-alerts"></div>';
$ret .= '<form role="form" class="form-horizontal" onsubmit="vendorEditor.saveVC(' . $id . '); return false;" id="vcForm">';
$ret .= '<div class="form-group">
<label for="vcAddress" class="control-label col-sm-1">Address</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="vcAddress" name="address" value="' . $model->address() . '" />
</div>
</div>';
$ret .= '<div class="form-group">
<label for="vcCity" class="control-label col-sm-1">City</label>
<div class="col-sm-5">
<input type="text" class="form-control" id="vcCity" name="city" value="' . $model->city() . '" />
</div>
<label for="vcZip" class="control-label col-sm-1">State</label>
<div class="col-sm-1">
<input type="text" class="form-control" id="vcState" name="state" value="' . $model->state() . '" />
</div>
<label for="vcZip" class="control-label col-sm-1">Zip</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="vcZip" name="zip" value="' . $model->zip() . '" />
</div>
</div>';
$ret .= '<div class="form-group">
<label for="vcPhone" class="control-label col-sm-1">Phone</label>
<div class="col-sm-5">
<input type="tel" class="form-control" id="vcPhone" name="phone" value="' . $model->phone() . '" />
</div>
<label for="vcFax" class="control-label col-sm-1">Fax</label>
<div class="col-sm-4">
<input type="text" id="vcFax" class="form-control" name="fax" value="' . $model->fax() . '" />
</div>
</div>';
$ret .= '<div class="form-group">
<label for="vcEmail" class="control-label col-sm-1">Email</label>
<div class="col-sm-5">
<input type="text" class="form-control" id="vcEmail" name="email" value="' . $model->email() . '" />
</div>
<label for="vcWebsite" class="control-label col-sm-1">Website</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="vcWebsite" name="website" value="' . $model->website() . '" />
</div>
</div>';
$ret .= '<div class="form-group">
<label for="vc-local-id" class="control-label col-sm-1">Local</label>
<div class="col-sm-10">
<select class="form-control" name="local-origin-id">
<option value="0">No</option>';
$origins = new OriginsModel($dbc);
$origins->local(1);
$locals = $origins->find('shortName');
if (count($locals) == 0) {
$ret .= sprintf('<option value="1" %s>Yes</option>',
($model->localOriginID() == 1 ? 'selected' : ''));
} else {
foreach ($locals as $origin) {
$ret .= sprintf('<option %s value="%d">%s</option>',
($origin->originID() == $model->localOriginID() ? 'selected' : ''),
$origin->originID(), $origin->shortName());
}
}
$ret .= '</select>
</div>
</div>';
$ret .= '<div class="form-group">
<label for="vcNotes" class="control-label col-sm-1">Ordering Notes</label>
<div class="col-sm-10">
<textarea class="form-control" rows="5" name="notes" id="vcNotes">' . $model->notes() . '</textarea>
</div>
</div>';
$ret .= '<button ' . $noEdit . ' type="submit" class="btn btn-default">Save Vendor Contact Info</button>';
$ret .= '</form>';
$ret .= '</div></div>';
$prodP = $dbc->prepare("SELECT super_name, count(*)
FROM products AS p
INNER JOIN MasterSuperDepts AS m ON p.department=m.dept_ID
WHERE p.default_vendor_id=?
GROUP BY super_name");
$prodR = $dbc->execute($prodP, array($id));
$supers = array();
$sum = 0;
while ($row = $dbc->fetchRow($prodR)) {
$supers[$row['super_name']] = $row[1];
$sum += $row[1];
}
arsort($supers);
foreach (array_keys($supers) as $s) {
$supers[$s] = sprintf('%.2f%%', $supers[$s] / $sum * 100);
}
$ret .= '<div class="panel panel-default">
<div class="panel-heading">Product Mix</div>
<div class="panel-body"><ul>';
foreach ($supers as $s => $pct) {
$ret .= '<li>' . $pct . ' ' . $s . '</li>';
}
$ret .= '</ul></div></div>';
$stores = new StoresModel($dbc);
$stores->hasOwnItems(1);
$map = new AutoOrderMapModel($dbc);
$map->vendorID($id);
$ret .= '<div class="panel panel-default">
<div class="panel-heading">Auto Order</div>
<div class="panel-body">
<div class="form-group">
<label>Minimum Order</label>
<div class="input-group">
<span class="input-group-addon">$</span>
<input type="text" name="minOrder" class="form-control auto-order"
value="' . $model->orderMinimum() . '" ' . $noEdit . ' />
</div>
</div>
<div class="form-group">
<label>Allow Half Cases
<input type="checkbox" name="halfs" class="auto-order" value="1"
' . ($model->halfCases() ? 'checked' : '') . ' ' . $noEdit . ' />
</label>
</div>
<table class="table table-bordered">
<tr><th>Store</th><th>Enabled</th><th>Account#</th></tr>';
foreach ($stores->find() as $store) {
$map->storeID($store->storeID());
$exists = $map->load();
$ret .= sprintf('<tr>
<td>%s</td>
<input type="hidden" name="autoID[]" value="%d" class="auto-order" />
<td><input type="checkbox" %s class="auto-order" name="autoEnable[]" value="%d" %s /></td>
<td><input type="text" class="form-control auto-order" name="autoAccount[]" value="%s" %s /></td>
</tr>',
$store->description(),
$store->storeID(),
($map->active() ? 'checked' : ''),
$store->storeID(), $noEdit,
$map->accountID(), $noEdit
);
}
$ret .= '</table>
<button type="button" class="btn btn-default" ' . $noEdit . '
onclick="vendorEditor.saveAutoOrder(' . $id . '); return false;">Save</button>
<a class="' . $noShow . '" href="ParsPage.php?id=' . $id . '">Pars Algorithm</a>
</div>
</div>';
$delivery = new VendorDeliveriesModel($dbc);
$delivery->vendorID($id);
$delivery->load();
$ret .= '<p class="form-inline form-group"><label class="control-label" for="deliverySelect">Delivery Schedule</label>: ';
$ret .= '<select class="delivery form-control" name="frequency" id="deliverySelect"><option>Weekly</option></select>';
$ret .= ' <label for="regular" class="control-label">Regular</label>: <input type="checkbox" class="delivery"
name="regular" id="regular" ' . ($delivery->regular() ? 'checked' : '') . ' />';
$dt = mktime(0, 0, 0, 6, 15, 2014); // date doesn't matter; just need a sunday
$labels = '';
$checks = '';
for ($i=0; $i<7; $i++) {
$func = strtolower(date('l', $dt));
$labels .= '<th><label for="' . $func . '">' . date('D', $dt) . '</label></th>';
$checks .= '<td><input type="checkbox" id="' . $func . '" name="' . $func . '"
' . ($delivery->$func() ? 'checked' : '') . ' class="delivery" ' . $noEdit . '/></td>';
$dt = mktime(0, 0, 0, date('n', $dt), date('j', $dt)+1, date('Y', $dt));
}
$ret .= '<table class="table"><tr>' . $labels . '</tr><tr>' . $checks . '</tr></table>';
$ret .= 'Next 2 deliveries: '
. '<span id="nextDelivery">' . date('D, M jS', strtotime($delivery->nextDelivery())) . '</span>'
. ' and '
. '<span id="nextNextDelivery">' . date('D, M jS', strtotime($delivery->nextNextDelivery())) . '</span>';
$ret .= '</p>';
echo $ret;
}
private function newVendor($name)
{
$dbc = FannieDB::get($this->config->get('OP_DB'));
$id = 1;
$p = $dbc->prepare("SELECT max(vendorID) FROM vendors");
$rp = $dbc->execute($p);
$rw = $dbc->fetch_row($rp);
if ($rw[0] != "")
$id = $rw[0]+1;
$model = new VendorsModel($dbc);
$model->vendorID($id);
$model->vendorName($name);
$model->vendorAbbreviation(substr($name, 0, 10));
$model->save();
return $id;
}
protected function get_view()
{
$dbc = FannieDB::get($this->config->get('OP_DB'));
$vendors = "<option value=\"\">Select a vendor...</option>";
$vendors .= "<option value=\"new\">New vendor...</option>";
$q = $dbc->prepare("SELECT * FROM vendors ORDER BY vendorName");
$rp = $dbc->execute($q);
$vid = FormLib::get_form_value('vid');
while($rw = $dbc->fetch_row($rp)){
if ($vid !== '' && $vid == $rw[0])
$vendors .= "<option selected value=$rw[0]>$rw[1]</option>";
else
$vendors .= "<option value=$rw[0]>$rw[1]</option>";
}
ob_start();
?>
<p id="vendorarea">
<select onchange="if (this.value=='new') vendorEditor.vendorNew(); else location='?vid='+this.value;"
id=vendorselect class="form-control chosen">
<?php echo $vendors; ?>
</select>
</p>
<p id="contentarea">
<?php
if ($vid) {
echo $this->getVendorInfo($vid);
$this->addOnloadCommand("\$('.delivery').change(vendorEditor.saveDelivery);\n");
}
?>
</p>
<?php
$this->addScript('index.js');
$this->addOnloadCommand("\$('#vendorselect').focus();\n");
$this->addScript('../../src/javascript/chosen/chosen.jquery.min.js');
$this->addCssFile('../../src/javascript/chosen/bootstrap-chosen.css');
$this->addOnloadCommand("\$('select.chosen').chosen();\n");
return ob_get_clean();
}
public function helpContent()
{
return '<p>Vendors are the entities the store purchases its
products from. The most important data associated with
a vendor is their catalog of items. A product that the store
sells may correspond to one or more items in one or more
catalogs - i.e. the item may be available from more than
one vendor and/or may be availalbe in more than one case
size. Keeping vendor catalogs up to date with accurate
costs helps manage retail pricing and margin.</p>
<p>There are two fairly distinct paths to managing vendor
catalogs. The best approach will differ depending what kind
of information is available for a given vendor. The first
approach begins with building a full vendor catalog. This
is more practical if the catalog is available in a digital
format. <em>Upload vendor catalog</em> is used to import
all the catalog data. From there <em>Browse vendor catalog</em>
can be used to add catalog items to the store\'s own products.
</p>
<p>The second approach begins with the store\'s own products
and builds a minimal vendor catalog to match. This is more
practical when a digital catalog is not available. <em>Add existing
items to catalog</em> will create vendor catalog entries from
the store\'s existing products that are assigned to this vendor.
<em>Edit vendor catalog</em> can then adjust these catalog
entries as needed. While <em>Edit vendor catalog</em> can technically
be used with catalog imported from digital files, this is a
waste of time if catalogs are imported on a regular basis. Each
subsequent import will end up overwriting all manual edits.
Similarly, you can <em>Browse vendor catalog</em> with catalogs
that were built from the store\'s existing products but there
won\'t be any items that can be added to products.
</p>
<p>PLU/SKU mapping is for resolving situations where the
store and the vendor use different UPCs. This is often
the case with items sold in bulk using a PLU.</p>
<p>Contact Info and Delivery Schedule are wholly optional.
Jot down whatever is useful.</p>
<p>Several margin adjustments can be associated with a vendor.
An item\'s default margin is chosen, from lowest to highest priority,
from these options:
<ul>
<li><em>(default)</em> The POS department\'s margin.</li>
<li>The vendor catalog subcategory\'s margin</li>
<li>The vendor <strong>and</strong> POS department specific margin</li>
</ul>
This structure creates increasingly specific overrides from the default, POS-department
based margins. Higher priority rules only need to exist where the target margin
deviates from the default. Both vendor subcategories and the additional vendor+POS-department
overrides are entirely optional.</p>
<p>Two additional adjustments can be applied <em>in addition</em> to the baseline margin above.
The shipping percentage <strong>increases</strong> the item\'s cost before applying the
baseline margin resulting in a higher retail price. The discount rate <strong>decreases</strong>
an item\'s cost before applying the baseline margin resulting in a lower retail price. The names
refer to common use cases, but in practice to price all a vendor\'s items e.g. 5% above or below
the default POS department margin it\'s easier to use one of these fields than create dozens and/or
hundreds of subcategory or vendor+POS-department overrides.</p>
';
}
public function unitTest($phpunit)
{
$phpunit->assertNotEquals(0, strlen($this->get_view()));
$new = $this->newVendor('TEST VENDOR');
$phpunit->assertEquals(true, is_numeric($new));
$this->id=$new;
$this->get_id_autoAdd_handler();
$this->rate=100;
$this->shipping=100;
ob_start();
$this->post_id_rate_handler();
$this->post_id_shipping_handler();
ob_end_clean();
$this->inactive = 0;
$this->post_id_inactive_handler();
$vendor = new VendorsModel($this->connection);
$vendor->vendorID($new);
$phpunit->assertEquals(true, $vendor->load());
$phpunit->assertEquals(1, $vendor->shippingMarkup());
$phpunit->assertEquals(1, $vendor->discountRate());
$phpunit->assertEquals(0, $vendor->inactive());
$this->name = 'TEST';
ob_start();
$this->post_new_name_handler();
$this->get_info_handler();
ob_end_clean();
}
}
FannieDispatch::conditionalExec();