function parse($str) { $ret = $this->default_json(); if (CoreLocal::get('isMember') !== 1) { $ret['output'] = DisplayLib::boxMsg(_("Apply member number first"), _('No member selected'), false, array_merge(array('Member Search [ID]' => 'parseWrapper(\'ID\');'), DisplayLib::standardClearButton())); return $ret; } elseif (CoreLocal::get('NeedDiscountFlag') == 1) { $ret['output'] = DisplayLib::boxMsg(_("discount already applied"), '', false, DisplayLib::standardClearButton()); return $ret; } else { CoreLocal::set('NeedDiscountFlag', 1); $NBDisc = CoreLocal::get('needBasedPercent') * 100; DiscountModule::updateDiscount(new DiscountModule($NBDisc, 'NeedBasedDiscount')); $ret['output'] = DisplayLib::lastpage(); $ret['redraw_footer'] = true; return $ret; } }
/** Assign a member number to a transaction @param $member CardNo from custdata @param $personNumber personNum from custdata See memberID() for more information. */ public static function setMember($member, $personNumber, $row = array()) { $conn = Database::pDataConnect(); /** Look up the member information here. There's no good reason to have calling code pass in a specially formatted row of data */ $query = "\n SELECT \n CardNo,\n personNum,\n LastName,\n FirstName,\n CashBack,\n Balance,\n Discount,\n ChargeOk,\n WriteChecks,\n StoreCoupons,\n Type,\n memType,\n staff,\n SSI,\n Purchases,\n NumberOfChecks,\n memCoupons,\n blueLine,\n Shown,\n id \n FROM custdata \n WHERE CardNo = " . (int) $member . "\n AND personNum = " . (int) $personNumber; $result = $conn->query($query); $row = $conn->fetch_row($result); CoreLocal::set("memberID", $member); CoreLocal::set("memType", $row["memType"]); CoreLocal::set("lname", $row["LastName"]); CoreLocal::set("fname", $row["FirstName"]); CoreLocal::set("Type", $row["Type"]); CoreLocal::set("isStaff", $row["staff"]); CoreLocal::set("SSI", $row["SSI"]); if (CoreLocal::get("Type") == "PC") { CoreLocal::set("isMember", 1); } else { CoreLocal::set("isMember", 0); } /** Optinonally use memtype table to normalize attributes by member type */ if (CoreLocal::get('useMemTypeTable') == 1 && $conn->table_exists('memtype')) { $prep = $conn->prepare('SELECT discount, staff, ssi FROM memtype WHERE memtype=?'); $res = $conn->execute($prep, array((int) CoreLocal::get('memType'))); if ($conn->num_rows($res) > 0) { $mt_row = $conn->fetch_row($res); $row['Discount'] = $mt_row['discount']; CoreLocal::set('isStaff', $mt_row['staff']); CoreLocal::set('SSI', $mt_row['ssi']); } } if (CoreLocal::get("isStaff") == 0) { CoreLocal::set("staffSpecial", 0); } /** Determine what string is shown in the upper left of the screen to indicate the current member */ $memMsg = '#' . $member; if (!empty($row['blueLine'])) { $memMsg = $row['blueLine']; } $chargeOk = self::chargeOk(); if (CoreLocal::get("balance") != 0 && $member != CoreLocal::get("defaultNonMem")) { $memMsg .= _(" AR"); } if (CoreLocal::get("SSI") == 1) { $memMsg .= " #"; } if ($conn->tableExists('CustomerNotifications')) { $blQ = ' SELECT message FROM CustomerNotifications WHERE cardNo=' . (int) $member . ' AND type=\'blueline\' ORDER BY message'; $blR = $conn->query($blQ); while ($blW = $conn->fetchRow($blR)) { $memMsg .= ' ' . $blW['message']; } } CoreLocal::set("memMsg", $memMsg); self::setAltMemMsg(CoreLocal::get("store"), $member, $personNumber, $row, $chargeOk); /** Set member number and attributes in the current transaction */ $conn2 = Database::tDataConnect(); $memquery = "\n UPDATE localtemptrans \n SET card_no = '" . $member . "',\n memType = " . sprintf("%d", CoreLocal::get("memType")) . ",\n staff = " . sprintf("%d", CoreLocal::get("isStaff")); $conn2->query($memquery); /** Add the member discount */ if (CoreLocal::get('discountEnforced')) { // skip subtotaling automatically since that occurs farther down DiscountModule::updateDiscount(new DiscountModule($row['Discount'], 'custdata'), false); } /** Log the member entry */ CoreLocal::set("memberID", $member); $opts = array('upc' => 'MEMENTRY', 'description' => 'CARDNO IN NUMFLAG', 'numflag' => $member); TransRecord::add_log_record($opts); /** Optionally add a subtotal line depending on member_subtotal setting. */ if (CoreLocal::get('member_subtotal') === 0 || CoreLocal::get('member_subtotal') === '0') { $noop = ""; } else { self::ttl(); } }
/** Get information about how much the coupon is worth @param $id [int] coupon ID @return array with keys: value => [float] coupon value department => [int] department number for the coupon description => [string] description for coupon */ public function getValue($id) { $infoW = $this->lookupCoupon($id); if ($infoW === false) { return array('value' => 0, 'department' => 0, 'description' => ''); } $transDB = Database::tDataConnect(); /* if we got this far, the coupon * should be valid */ $value = 0; $coupID = $id; $description = isset($infoW['description']) ? $infoW['description'] : ''; switch ($infoW["discountType"]) { case "Q": // quantity discount // discount = coupon's discountValue // times the cheapeast coupon item $valQ = "select unitPrice, department \n " . $this->baseSQL($transDB, $coupID, 'upc') . "\n and h.type in ('BOTH', 'DISCOUNT')\n and l.total > 0\n order by unitPrice asc "; $valR = $transDB->query($valQ); $valW = $transDB->fetch_row($valR); $value = $valW[0] * $infoW["discountValue"]; break; case "P": // discount price // query to get the item's department and current value // current value minus the discount price is how much to // take off $value = $infoW["discountValue"]; $deptQ = "select department, (total/quantity) as value \n " . $this->baseSQL($transDB, $coupID, 'upc') . "\n and h.type in ('BOTH', 'DISCOUNT')\n and l.total > 0\n order by unitPrice asc "; $deptR = $transDB->query($deptQ); $row = $transDB->fetch_row($deptR); $value = $row[1] - $value; break; case "FD": // flat discount for departments // simply take off the requested amount // scales with quantity for by-weight items $value = $infoW["discountValue"]; $valQ = "select department, quantity \n " . $this->baseSQL($transDB, $coupID, 'department') . "\n and h.type in ('BOTH', 'DISCOUNT')\n and l.total > 0\n order by unitPrice asc "; $valR = $transDB->query($valQ); $row = $transDB->fetch_row($valR); $value = $row[1] * $value; break; case "MD": // mix discount for departments // take off item value or discount value // whichever is less $value = $infoW["discountValue"]; $valQ = "select department, l.total \n " . $this->baseSQL($transDB, $coupID, 'department') . "\n and h.type in ('BOTH', 'DISCOUNT')\n and l.total > 0\n order by l.total desc "; $valR = $transDB->query($valQ); $row = $transDB->fetch_row($valR); $value = $row[1] < $value ? $row[1] : $value; break; case "AD": // all department discount // apply discount across all items // scales with quantity for by-weight items $value = $infoW["discountValue"]; $valQ = "select sum(quantity) \n " . $this->baseSQL($transDB, $coupID, 'department') . "\n and h.type in ('BOTH', 'DISCOUNT')\n and l.total > 0\n order by unitPrice asc "; $valR = $transDB->query($valQ); $row = $transDB->fetch_row($valR); $value = $row[1] * $value; break; case "FI": // flat discount for items // simply take off the requested amount // scales with quantity for by-weight items $value = $infoW["discountValue"]; $valQ = "select l.upc, quantity \n " . $this->baseSQL($transDB, $coupID, 'upc') . "\n and h.type in ('BOTH', 'DISCOUNT')\n and l.total > 0\n order by unitPrice asc"; $valR = $transDB->query($valQ); $row = $transDB->fetch_row($valR); $value = $row[1] * $value; break; case 'PI': // per-item discount // take of the request amount times the // number of matching items. $value = $infoW["discountValue"]; $valQ = "\n SELECT \n SUM(CASE WHEN ItemQtty IS NULL THEN 0 ELSE ItemQtty END) AS qty\n " . $this->baseSQL($transDB, $coupID, 'upc'); $valR = $transDB->query($valQ); $row = $transDB->fetch_row($valR); $value = $row['qty'] * $value; break; case "F": // completely flat; no scaling for weight $value = $infoW["discountValue"]; break; case "%": // percent discount on all items Database::getsubtotals(); $value = $infoW["discountValue"] * CoreLocal::get("discountableTotal"); break; case "%B": // better percent discount applies Database::getsubtotals(); $coupon_discount = (int) ($infoW['discountValue'] * 100); if ($coupon_discount <= CoreLocal::get('percentDiscount')) { // customer's discount is better than coupon discount; skip // applying coupon $value = 0; } else { // coupon discount is better than customer's discount // apply coupon & zero out customer's discount $value = $infoW["discountValue"] * CoreLocal::get("discountableTotal"); CoreLocal::set('percentDiscount', 0); $transDB->query('UPDATE localtemptrans SET percentDiscount=0'); } break; case "%D": // percent discount on all items in give department(s) $valQ = "select sum(total) \n " . $this->baseSQL($transDB, $coupID, 'department') . "\n and h.type in ('BOTH', 'DISCOUNT')"; $valR = $transDB->query($valQ); $row = $transDB->fetch_row($valR); $value = $row[0] * $infoW["discountValue"]; break; case "%E": // better percent discount applies to specified department only Database::getsubtotals(); $coupon_discount = (int) ($infoW['discountValue'] * 100); if ($coupon_discount <= CoreLocal::get('percentDiscount')) { // customer's discount is better than coupon discount; skip // applying coupon $value = 0; } else { // coupon discount is better than customer's discount // apply coupon & exclude those items from customer's discount $valQ = "select sum(total) \n " . $this->baseSQL($transDB, $coupID, 'department') . "\n and h.type in ('BOTH', 'DISCOUNT')"; $valR = $transDB->query($valQ); $row = $transDB->fetch_row($valR); $value = $row[0] * $infoW["discountValue"]; $clearQ = "\n UPDATE localtemptrans AS l \n INNER JOIN " . CoreLocal::get('pDatabase') . $transDB->sep() . "houseCouponItems AS h ON l.department = h.upc\n SET l.discountable=0\n WHERE h.coupID = " . $coupID . "\n AND h.type IN ('BOTH', 'DISCOUNT')"; $clearR = $transDB->query($clearR); } break; case 'PD': // modify customer percent discount // rather than add line-item $couponPD = $infoW['discountValue'] * 100; DiscountModule::updateDiscount(new DiscountModule($couponPD, 'HouseCoupon')); // still need to add a line-item with the coupon UPC to the // transaction to track usage $value = 0; $description = $couponPD . ' % Discount Coupon'; break; case 'OD': // override customer percent discount // rather than add line-item $couponPD = $infoW['discountValue'] * 100; DiscountModule::updateDiscount(new DiscountModule(0, 'custdata')); DiscountModule::updateDiscount(new DiscountModule($couponPD, 'HouseCoupon')); // still need to add a line-item with the coupon UPC to the // transaction to track usage $value = 0; $description = $couponPD . ' % Discount Coupon'; break; } return array('value' => $value, 'department' => $infoW['department'], 'description' => $description); }
public function testDiscountModules() { $ten = new DiscountModule(10, 'ten'); $fifteen = new DiscountModule(15, 'fifteen'); // verify stacking discounts CoreLocal::set('percentDiscount', 0); CoreLocal::set('NonStackingDiscounts', 0); DiscountModule::updateDiscount($ten, false); $this->assertEquals(10, CoreLocal::get('percentDiscount')); DiscountModule::updateDiscount($fifteen, false); $this->assertEquals(25, CoreLocal::get('percentDiscount')); DiscountModule::transReset(); // verify non-stacking discounts CoreLocal::set('percentDiscount', 0); CoreLocal::set('NonStackingDiscounts', 1); DiscountModule::updateDiscount($ten, false); $this->assertEquals(10, CoreLocal::get('percentDiscount')); DiscountModule::updateDiscount($fifteen, false); $this->assertEquals(15, CoreLocal::get('percentDiscount')); DiscountModule::transReset(); // verify best non-stacking discount wins CoreLocal::set('percentDiscount', 0); DiscountModule::updateDiscount($fifteen, false); $this->assertEquals(15, CoreLocal::get('percentDiscount')); DiscountModule::updateDiscount($ten, false); $this->assertEquals(15, CoreLocal::get('percentDiscount')); DiscountModule::transReset(); // verify same-name discounts overwrite $one = new DiscountModule(1, 'custdata'); $two = new DiscountModule(2, 'custdata'); CoreLocal::set('percentDiscount', 0); CoreLocal::set('NonStackingDiscounts', 0); DiscountModule::updateDiscount($one, false); $this->assertEquals(1, CoreLocal::get('percentDiscount')); DiscountModule::updateDiscount($two, false); $this->assertEquals(2, CoreLocal::get('percentDiscount')); DiscountModule::transReset(); // same-name should overwrite in the order called CoreLocal::set('percentDiscount', 0); DiscountModule::updateDiscount($two, false); $this->assertEquals(2, CoreLocal::get('percentDiscount')); DiscountModule::updateDiscount($one, false); $this->assertEquals(1, CoreLocal::get('percentDiscount')); }