pos/is4c-nf/plugins/CoopCred/CoopCredLib.php
<?php
/*******************************************************************************
Copyright 2012 Whole Foods Co-op
Copyright 2014 West End Food Co-op, Toronto
This file is part of IT CORE.
IT CORE 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.
IT CORE 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
*********************************************************************************/
use COREPOS\pos\lib\ReceiptLib;
/**
@class CoopCredLib
Functions for the Coop Cred plugin.
*/
class CoopCredLib {
static private $SQL_CONNECTION = null;
static public function cclibtest ()
{
return 'OK';
}
/**
Whether OK to use Coop Cred. Assign balance and availBal.
@return 1 if OK, 0 if not.
Never used, may never be and is therefore deprecated.
Originally intended for making usage more like other tenders.
At this point is not program-specific so hard to see its use.
The assignments are in getCCredSubtotals().
$tender isn't needed.
*/
static public function chargeOK($tender='')
{
global $CORE_LOCAL;
/*
* I'm commenting this out because using $this in a static conext
* is not allowed. I'm not 100% sure what this used to do.
* I think attempts to get variables via $this would yield
* NULLs but I haven't found clear documentation saying that.
* I added a line that I believe preserves the functionality
* but it really is just a guess
*
$availBal = $this->availCreditBalance + $CORE_LOCAL->get("memChargeTotal");
$CORE_LOCAL->set("balance",$this->creditBalance);
$CORE_LOCAL->set("availBal",number_format($availBal,2,'.',''));
*/
$CORE_LOCAL->set("availBal", number_format($CORE_LOCAL->get('memChargeTotal'), 2, '.', ''));
$chargeOk = 1;
/* This check has already been done.
if ($num_rows == 0 || !$row["ChargeOk"]) {
$chargeOk = 0;
} elseif ( $row["ChargeOk"] == 0 ) {
$chargeOk = 0;
}
*/
return $chargeOk;
// chargeOK()
}
/**
OK to use the tender or make the input?
@return True if all clear to charge or input to the program
message if not
@param $pKey - a tenderType or paymentDepartment
Note: Transfer-to-another member part is not done.
*
* Knowing tenderType or paymentDepartment and memberID
* Step 1:
* - Find the program
* Step 2:
* - Is the program active?
* Step 3:
* - Is the member in it? CCredMemberships record exists.
* - Is the membership in the program active?
* x Is there enough to cover the amount?
*/
static public function programOK($pKey='', $conn='')
{
global $CORE_LOCAL;
if (!$CORE_LOCAL->get("memberID")) {
return _("Please enter the Member ID");
}
if ($conn == '') {
$conn = self::ccDataConnect();
if (!is_object($conn)){
return _("Coop Cred database connection failed:") . " {$conn}";
}
}
$pKeyType = (preg_match('/^\d+$/',$pKey)) ? 'Department' : 'Tender';
$ccpModel = new CCredProgramsModel($conn);
if ($pKeyType == 'Department') {
$ccpModel->paymentDepartment($pKey);
} else {
$ccpModel->tenderType($pKey);
}
$pCount = 0;
foreach($ccpModel->find() as $pgm) {
$pCount++;
//$limit = $cdModel->ChargeLimit();
//$prog['inputOK'] = $pgm->inputOK();
}
if ($pCount == 0) {
return _("Error:") ." {$pKeyType}" . " '{$pKey}' " .
_("is not used in any Coop Cred Program.");
}
if ($pCount > 1) {
return _("Error:") ." {$pKeyType}" . " '{$pKey}' " .
_("is used in more than one Coop Cred Program.");
}
$today = date('Y-m-d');
if ($today < $pgm->startDate()) {
return $pgm->programName() . _(" hasn't started yet.");
}
if ($today < $pgm->endDate() != '' && $today > $pgm->endDate()) {
return $pgm->programName() . _(" is no longer operating.");
}
if (!$pgm->active()) {
return $pgm->programName() . _(" is not active.");
}
if (!$pgm->creditOK()) {
return $pgm->programName() . _(" is not accepting purchases at this time.");
}
/* These are only valid globally for calculations involving the
* current tenderType or paymentDepartment.
*/
$CORE_LOCAL->set("CCredProgramID",$pgm->programID());
$programCode = "CCred{$pgm->programID()}";
$CORE_LOCAL->set("CCredProgramCode",$programCode);
/* Reset these in CoopCred::plugin_transaction_reset()
*/
$CORE_LOCAL->set("{$programCode}programID",$pgm->programID());
$CORE_LOCAL->set("{$programCode}programName",$pgm->programName());
$CORE_LOCAL->set("{$programCode}paymentDepartment",$pgm->paymentDepartment());
$CORE_LOCAL->set("{$programCode}paymentName",$pgm->paymentName());
$CORE_LOCAL->set("{$programCode}paymentKeyCap",$pgm->paymentKeyCap());
$CORE_LOCAL->set("{$programCode}tenderType",$pgm->tenderType());
$CORE_LOCAL->set("{$programCode}tenderName",$pgm->tenderName());
$CORE_LOCAL->set("{$programCode}tenderKeyCap",$pgm->tenderKeyCap());
/* Membership info.
* (At the moment members's name is not used, so a model query could be used.)
*/
$query = "SELECT m.creditBalance, m.creditLimit, m.creditOK, m.inputOK,
m.transferOK, m.isBank
,(m.creditLimit - m.creditBalance) as availCreditBalance
,c.FirstName, c.LastName
FROM CCredMemberships m
JOIN {$CORE_LOCAL->get('pDatabase')}.custdata c
ON m.cardNo = c.CardNo
WHERE m.cardNo = ? AND m.programID = ? AND c.personNum=1";
$statement = $conn->prepare($query);
if ($statement === False) {
return "Error: prepare() failed for query: $query";
}
$args=array(
(int)$CORE_LOCAL->get("memberID"),
(int)$pgm->programID()
);
$result = $conn->execute($statement,$args);
if ($result === False) {
return "Error: execute() failed for query: $query args:" .
implode('|',$args);
}
$num_rows = $conn->num_rows($result);
if ($num_rows == 0) {
return _("Member ") .
$CORE_LOCAL->get("memberID") .
_(" is not registered for ") .
$CORE_LOCAL->get("{$programCode}programName") .
".";
}
$mem = $conn->fetchRow($result);
/* Suspended or not activated for either purchasing or input.
*/
if (!$mem['creditOK']) {
return _("Member #") .
$CORE_LOCAL->get("memberID") .
_(" is registered for ") .
'<b>'. $CORE_LOCAL->get("{$programCode}programName"). '</b>' .
_(" but may not use it") .
_(" at this time") . ".";
}
/* May not put money into the program.
*/
if ($pKeyType == "Department" && !$mem['inputOK']) {
return _("Member #") .
$CORE_LOCAL->get("memberID") .
_(" may not pay into ") .
$CORE_LOCAL->get("{$programCode}programName") .
".";
}
/* May not transfer to another member.
* I can't think how this could be done at cash without a special popup.
* Transfer among one's own accounts: input to one, tender from another.
* Test would be at point of tender and need a scan of localtemptrans
* for CoopCredDepartments, $CoopCredDepartmentsUsed.
* "Payments" better, "Inputs" even better.
* AND trans_status in ('','0') - not cancel, void, refund - what would that be?
*/
$isTransfer = 0;
if (!$mem['transferOK'] && $isTransfer) {
return _("Member #") .
$CORE_LOCAL->get("memberID") .
_(" may not transfer Coop Cred to another Member") .
".";
}
$CORE_LOCAL->set("{$programCode}availCreditBalance",$mem['availCreditBalance']);
$CORE_LOCAL->set("{$programCode}creditBalance",$mem['creditBalance']);
return True;
// programOK()
}
/**
Calculate Coop Cred-related subtotals for the named tender
in the current transaction.
@param $tender
@param $programCode
@param $table, default to localtemptrans for during-transaction,
but localtranstoday for end of transaction.
@param $ref emp-lane-trans, if needed for end of transaction
@return True or error message string.
*/
static public function getCCredSubtotals($tender, $conn,
$programCode='', $table='', $ref='')
{
global $CORE_LOCAL;
$pc = ($programCode != '') ? $programCode : $CORE_LOCAL->get("CCredProgramCode");
//$pc = ($programCode != '') ? $programCode : $CORE_LOCAL->get("programCode");
if ($table == '') {
$table = 'localtemptrans';
$refSQL = '';
} else {
if ($ref == '') {
$ref = ReceiptLib::mostRecentReceipt();
if ($ref === false) {
return "Cannot find most recent receipt";
}
}
$refs = explode('-',$ref);
$refSQL =
' AND emp_no =' . $refs[0] .
' AND register_no =' . $refs[1] .
' AND trans_no =' . $refs[2];
}
$subsQ = "SELECT
SUM(CASE
WHEN trans_subtype = '{$tender}'
THEN total
ELSE 0 END) AS chargeTotal,
SUM(CASE
WHEN department=" . $CORE_LOCAL->get("{$pc}paymentDepartment") .
" THEN total
ELSE 0 END) as paymentTotal
FROM " . $CORE_LOCAL->get("tDatabase") . ".$table
WHERE trans_type <> 'L'{$refSQL}";
$subsR = $conn->query("$subsQ");
if ($subsR === False) {
return "Error: query() failed for query: $subsQ";
} else {
$row = $conn->fetchRow($subsR);
$CORE_LOCAL->set("{$pc}chargeTotal",
(!$row || !isset($row['chargeTotal']))
? 0 : (double)$row["chargeTotal"] );
$CORE_LOCAL->set("{$pc}paymentTotal",
(!$row || !isset($row['paymentTotal']))
? 0 : (double)$row["paymentTotal"] );
$CORE_LOCAL->set("{$pc}memChargeTotal",
$CORE_LOCAL->get("{$pc}chargeTotal") +
$CORE_LOCAL->get("{$pc}paymentTotal") );
}
$availBal = (($CORE_LOCAL->get("{$pc}availCreditBalance") == '')
? 0 : $CORE_LOCAL->get("{$pc}availCreditBalance")) +
$CORE_LOCAL->get("{$pc}memChargeTotal");
$CORE_LOCAL->set("{$pc}availBal",number_format($availBal,2,'.',''));
$CORE_LOCAL->set("{$pc}balance",
(($CORE_LOCAL->get("{$pc}creditBalance") == '')
? 0 : $CORE_LOCAL->get("{$pc}creditBalance"))
);
return True;
// getCCredSubtotals()
}
/**
Connect to the coop cred database (local)
@return a SQLManager object
*/
static public function ccDataConnect()
{
global $CORE_LOCAL;
if (self::$SQL_CONNECTION === null){
/**
Create the connection object and add all local databases to it.
*/
self::$SQL_CONNECTION = new \COREPOS\pos\lib\SQLManager($CORE_LOCAL->get("localhost"),
$CORE_LOCAL->get("DBMS"),
$CORE_LOCAL->get("tDatabase"),
$CORE_LOCAL->get("localUser"),$CORE_LOCAL->get("localPass"),
False);
self::$SQL_CONNECTION->db_types[$CORE_LOCAL->get('pDatabase')] =
strtoupper($CORE_LOCAL->get('DBMS'));
self::$SQL_CONNECTION->connections[$CORE_LOCAL->get('pDatabase')] =
self::$SQL_CONNECTION->connections[$CORE_LOCAL->get('tDatabase')];
self::$SQL_CONNECTION->db_types[$CORE_LOCAL->get('CoopCredLaneDatabase')] =
strtoupper($CORE_LOCAL->get('DBMS'));
self::$SQL_CONNECTION->connections[$CORE_LOCAL->get('CoopCredLaneDatabase')] =
self::$SQL_CONNECTION->connections[$CORE_LOCAL->get('tDatabase')];
self::$SQL_CONNECTION->query('use '.$CORE_LOCAL->get('CoopCredLaneDatabase'));
self::$SQL_CONNECTION->default_db = $CORE_LOCAL->get('CoopCredLaneDatabase');
} else {
self::$SQL_CONNECTION->query('use '.$CORE_LOCAL->get('CoopCredLaneDatabase'));
self::$SQL_CONNECTION->default_db = $CORE_LOCAL->get('CoopCredLaneDatabase');
}
return self::$SQL_CONNECTION;
// ccDataConnect()
}
/**
Add the department to the list of payment departments in the current transaction.
@return True or False
*/
static public function addDepartmentUsed($paymentDepartment=0,$programID=0)
{
global $CORE_LOCAL;
/* I think it could default to using the current ones set by programOK()
*/
if (!$paymentDepartment || !$programID) {
return False;
}
/* Add the department to those input to in this transaction.
*/
if ($CORE_LOCAL->get('CCredDepartmentsUsed') == '') {
$CORE_LOCAL->set('CCredDepartmentsUsed', array(
"$paymentDepartment" => $programID
));
} else {
// Is there a push() or append()?
$du = $CORE_LOCAL->get('CCredDepartmentsUsed');
if (!array_key_exists("$paymentDepartment", $du)) {
$du["$paymentDepartment"] = $programID;
$CORE_LOCAL->set('CCredDepartmentsUsed',$du);
}
}
return True;
// addDepartmentUsed()
}
// CoopCredLib class
}