408 lines
14 KiB
PHP
408 lines
14 KiB
PHP
<?php
|
|
|
|
class Crunchbutton_Credit extends Cana_Table
|
|
{
|
|
const TYPE_CREDIT = 'CREDIT';
|
|
const TYPE_DEBIT = 'DEBIT';
|
|
|
|
const PAID_BY_CRUNCHBUTTON = 'crunchbutton';
|
|
const PAID_BY_RESTAURANT = 'restaurant';
|
|
const PAID_BY_PROMOTIONAL = 'promotional';
|
|
const PAID_BY_OTHER_RESTAURANT = 'other_restaurant';
|
|
|
|
public function __construct($id = null) {
|
|
parent::__construct();
|
|
$this
|
|
->table('credit')
|
|
->idVar('id_credit')
|
|
->load($id);
|
|
}
|
|
|
|
public function creditByUser( $id_user ) {
|
|
return Crunchbutton_Credit::q('SELECT * FROM credit WHERE type = "' . self::TYPE_CREDIT . '" AND id_user="'.$id_user.'"');
|
|
}
|
|
|
|
public function debitByUser( $id_user ) {
|
|
return Crunchbutton_Credit::q('SELECT * FROM credit WHERE type = "' . self::TYPE_DEBIT . '" AND id_user="'.$id_user.'"');
|
|
}
|
|
|
|
public function creditByUserRestaurant( $id_user, $id_restaurant ) {
|
|
if (!$id_user) {
|
|
return 0;
|
|
}
|
|
$credits = 0;
|
|
$query = 'SELECT SUM(`value`) as credit FROM ( SELECT SUM(`value`) as `value` FROM credit WHERE type = "' . self::TYPE_CREDIT . '" AND id_user = '.$id_user.' AND id_restaurant = ' . $id_restaurant . ' UNION SELECT SUM(`value`) * -1 as `value` FROM credit WHERE type = "' . self::TYPE_DEBIT . '" AND id_user = '.$id_user.' AND id_restaurant = ' . $id_restaurant . ' ) credit';
|
|
$row = Cana::db()->get( $query );
|
|
if( $row->_items && $row->_items[0] ){
|
|
if( $row->_items[0]->credit ){
|
|
$credits = floatval( $row->_items[0]->credit );
|
|
}
|
|
}
|
|
$anyRestaurantCredits = Crunchbutton_Credit::creditByUserValidToAnyRestaurant( $id_user );
|
|
return floatval( $credits + $anyRestaurantCredits );
|
|
}
|
|
|
|
public function creditByUserValidToAnyRestaurant( $id_user ){
|
|
if (!$id_user) {
|
|
return 0;
|
|
}
|
|
$query = 'SELECT SUM(`value`) as debit FROM ( SELECT SUM(`value`) as `value` FROM credit WHERE type = "' . self::TYPE_CREDIT . '" AND id_user = '.$id_user.' AND id_restaurant IS NULL UNION SELECT SUM( value ) * -1 FROM credit WHERE id_credit_debited_from IN ( SELECT id_credit FROM credit WHERE type = "' . self::TYPE_CREDIT . '" AND id_user = '.$id_user.' AND id_restaurant IS NULL ) ) debit';
|
|
$row = Cana::db()->get( $query );
|
|
if( $row->_items && $row->_items[0] ){
|
|
if( $row->_items[0]->debit ){
|
|
return floatval( $row->_items[0]->debit );
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public function totalDebitedFromCredit(){
|
|
$query = 'SELECT SUM(`value`) as `debited` FROM credit WHERE type = "' . self::TYPE_DEBIT . '" AND id_credit_debited_from = ' . $this->id_credit;
|
|
$row = Cana::db()->get( $query );
|
|
if( $row->_items && $row->_items[0] ){
|
|
if( $row->_items[0]->debited ){
|
|
return floatval( $row->_items[0]->debited );
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public static function find($search = []) {
|
|
|
|
$query = 'SELECT `credit`.* FROM `credit` LEFT JOIN restaurant USING(id_restaurant) WHERE id_credit IS NOT NULL ';
|
|
|
|
if ($search['type']) {
|
|
$query .= ' and type="'.$search['type'].'" ';
|
|
}
|
|
|
|
if ($search['start']) {
|
|
$s = new DateTime($search['start']);
|
|
$query .= ' and DATE(`date`)>="'.$s->format('Y-m-d').'" ';
|
|
}
|
|
|
|
if ($search['end']) {
|
|
$s = new DateTime($search['end']);
|
|
$query .= ' and DATE(`date`)<="'.$s->format('Y-m-d').'" ';
|
|
}
|
|
|
|
if ($search['restaurant']) {
|
|
$query .= ' and `credit`.id_restaurant="'.$search['restaurant'].'" ';
|
|
}
|
|
|
|
if ($search['id_order']) {
|
|
$query .= ' and `credit`.id_order="'.$search['id_order'].'" ';
|
|
}
|
|
|
|
if ($search['id_user']) {
|
|
$query .= ' and `credit`.id_user="'.$search['id_user'].'" ';
|
|
}
|
|
|
|
$query .= 'ORDER BY `date` DESC';
|
|
|
|
if ($search['limit']) {
|
|
$query .= ' limit '.$search['limit'].' ';
|
|
}
|
|
|
|
$credits = self::q($query);
|
|
return $credits;
|
|
}
|
|
|
|
public function date() {
|
|
if (!isset($this->_date)) {
|
|
$this->_date = new DateTime($this->date, new DateTimeZone(c::config()->timezone));
|
|
$this->_date->setTimezone(new DateTimeZone( c::config()->timezone ));
|
|
}
|
|
return $this->_date;
|
|
}
|
|
|
|
public function creditByOrder( $id_order ) {
|
|
return Crunchbutton_Credit::q('SELECT * FROM credit WHERE id_order="'.$id_order.'"');
|
|
}
|
|
|
|
public function creditByOrderPaidBy( $id_order, $paid_by ) {
|
|
$query = 'SELECT SUM(`value`) as credit FROM credit WHERE id_order = ' . $id_order . ' AND type = "' . Crunchbutton_Credit::TYPE_DEBIT . '" AND paid_by = "' . $paid_by . '"';
|
|
$row = Cana::db()->get( $query );
|
|
if( $row->_items && $row->_items[0] ){
|
|
if( $row->_items[0]->credit ){
|
|
return $row->_items[0]->credit;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public function debitHistory(){
|
|
return Crunchbutton_Credit::q('SELECT * FROM credit WHERE id_credit_debited_from="'.$this->id_credit.'"');
|
|
}
|
|
|
|
public function calcDebitFromUserCredit( $valueToCharge, $id_user, $id_restaurant ){
|
|
return Crunchbutton_Credit::debitFromUserCredit( $valueToCharge, $id_user, $id_restaurant, 0, true );
|
|
}
|
|
|
|
public function debitFromUserCredit( $valueToCharge, $id_user, $id_restaurant, $id_order = 0, $justCalc = false ){
|
|
$credit = Crunchbutton_Credit::creditByUserRestaurant( $id_user, $id_restaurant );
|
|
$totalCharged = 0;
|
|
$charge = $valueToCharge;
|
|
// It means the user has credit
|
|
if( $credit > 0 ){
|
|
$chargeLeft = $charge;
|
|
// Now I need to share the total at the credits availabe
|
|
$credits_available = Crunchbutton_Credit::creditsAvailableByUserRestaurant( $id_user, $id_restaurant );
|
|
$credits_charge = array();
|
|
if( count( $credits_available ) > 0 ){
|
|
// Divide the same amount to each credit
|
|
$charge_divided = Util::ceil( $charge / count( $credits_available ), 2);
|
|
// Because the number is rounded I need to do this verification to not charge more of the user
|
|
// if the $total is more then the $charge i just subtract the excendent from the first charge
|
|
$total = $charge_divided * count( $credits_available );
|
|
$first_charge = false;
|
|
if( $total > $charge ){
|
|
$first_charge = $charge_divided - ( $total - $charge );
|
|
}
|
|
foreach ($credits_available as $credit) {
|
|
if( $first_charge ){
|
|
$chargeOfThisCredit = $first_charge;
|
|
$first_charge = false;
|
|
} else {
|
|
$chargeOfThisCredit = $charge_divided;
|
|
}
|
|
|
|
// returns how much left of this credit
|
|
$left = $credit->creditLeft();
|
|
|
|
// If the left if less than the total do charge, just charge the left.
|
|
if( $left < $chargeOfThisCredit ){
|
|
$chargeOfThisCredit = $left;
|
|
}
|
|
// Update the chargeLeft value
|
|
$chargeLeft = $chargeLeft - $chargeOfThisCredit;
|
|
// Populate the array
|
|
$credits_charge[] = array( 'id_credit' => $credit->id_credit, 'charge' => $chargeOfThisCredit, 'left' => $left, 'credit' => $credit );
|
|
}
|
|
|
|
// If there are more to charge, lets use check again if we can use more of the user's credit
|
|
if( $chargeLeft > 0 ){
|
|
foreach( $credits_charge as $key => $value ){
|
|
if( $chargeLeft <= 0 ){
|
|
continue;
|
|
}
|
|
$left = $credits_charge[ $key ][ 'left' ];
|
|
$charge = $credits_charge[ $key ][ 'charge' ];
|
|
if( $charge < $left ){
|
|
if( $left >= ( $charge + $chargeLeft ) ){
|
|
$tryCharge = $charge + $chargeLeft;
|
|
$chargeLeft = 0;
|
|
} else {
|
|
$tryCharge = $left;
|
|
$chargeLeft = $left - $charge;
|
|
}
|
|
$credits_charge[ $key ][ 'charge' ] = $tryCharge;
|
|
}
|
|
}
|
|
}
|
|
// Finally all is calculate, let's debit the credits
|
|
foreach( $credits_charge as $key => $value ){
|
|
$credit = $credits_charge[ $key ][ 'credit' ];
|
|
$charge = $credits_charge[ $key ][ 'charge' ];
|
|
// At the first time I need just the calc, so do not charge for while
|
|
if( !$justCalc ){
|
|
$credit->charge( $charge, $id_order );
|
|
}
|
|
$totalCharged = $totalCharged + $charge;
|
|
}
|
|
}
|
|
}
|
|
return $totalCharged;
|
|
}
|
|
|
|
public function creditSpent(){
|
|
$query = 'SELECT SUM( value ) as spent FROM credit c WHERE type = "DEBIT" AND id_credit_debited_from = ' . $this->id_credit;
|
|
$row = Cana::db()->get( $query );
|
|
if( $row->_items && $row->_items[0] ){
|
|
$row = $row->_items[0];
|
|
return ( $row->spent < 0 ) ? 0 : $row->spent;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public function creditLeft(){
|
|
$spent = $this->creditSpent();
|
|
return $this->value - $spent;
|
|
}
|
|
|
|
public function removeCreditLeft(){
|
|
$spent = $this->creditSpent();
|
|
$valueToRemove = $this->value - $spent;
|
|
// Create a new debit to remove this credit
|
|
$credit = new Crunchbutton_Credit();
|
|
$credit->id_user = $this->id_user;
|
|
$credit->type = Crunchbutton_Credit::TYPE_DEBIT;
|
|
$credit->id_restaurant = $this->id_restaurant;
|
|
$credit->date = date('Y-m-d H:i:s');
|
|
$credit->value = $valueToRemove;
|
|
$credit->id_order = $id_order;
|
|
$credit->paid_by = $this->paid_by;
|
|
$credit->id_restaurant_paid_by = $this->id_restaurant_paid_by;
|
|
$credit->id_credit_debited_from = $this->id_credit;
|
|
$credit->note = 'Removed the credit #' . $this->id_credit . ' ($' . $valueToRemove . ') - by: ' . c::admin()->name;
|
|
$credit->save();
|
|
}
|
|
|
|
public function charge( $value, $id_order ){
|
|
$credit = new Crunchbutton_Credit();
|
|
$credit->id_user = $this->id_user;
|
|
$credit->type = Crunchbutton_Credit::TYPE_DEBIT;
|
|
$credit->id_restaurant = $this->id_restaurant;
|
|
$credit->date = date('Y-m-d H:i:s');
|
|
$credit->value = $value;
|
|
$credit->id_order = $id_order;
|
|
$credit->paid_by = $this->paid_by;
|
|
$credit->id_restaurant_paid_by = $this->id_restaurant_paid_by;
|
|
$credit->id_credit_debited_from = $this->id_credit;
|
|
$credit->save();
|
|
}
|
|
|
|
public function creditsAvailableByUserRestaurant( $id_user, $id_restaurant ){
|
|
$credit_available = array();
|
|
$credits = Crunchbutton_Credit::q( 'SELECT * FROM credit WHERE type = "' . self::TYPE_CREDIT . '" AND id_user="'.$id_user.'" AND ( id_restaurant = '.$id_restaurant.' OR id_restaurant IS NULL )' );
|
|
if( $credits->count() > 0 ){
|
|
foreach( $credits as $credit ){
|
|
$left = $credit->creditLeft();
|
|
if( $left > 0 ){
|
|
// $credit_available[] = array( 'credit' => floatval( $credit->value ), 'left' => floatval( $left ), 'id_restaurant' => $credit->id_restaurant );
|
|
$credit_available[] = $credit;
|
|
}
|
|
}
|
|
}
|
|
return $credit_available;
|
|
}
|
|
|
|
public function antifraudByUser( $creditMoreThan = 10 ){
|
|
$query = "SELECT (credit - COALESCE( debits.debit, 0)) AS credit_left,
|
|
credits.credit,
|
|
COALESCE( debits.debit, 0) AS debit,
|
|
credits.id_user
|
|
FROM
|
|
(SELECT SUM(c.value) AS credit,
|
|
u.id_user
|
|
FROM credit c
|
|
INNER JOIN user u ON u.id_user = c.id_user
|
|
WHERE c.type = 'CREDIT'
|
|
GROUP BY u.id_user HAVING credit > {$creditMoreThan}) credits
|
|
LEFT JOIN
|
|
(SELECT SUM(c.value) AS debit,
|
|
u.id_user
|
|
FROM credit c
|
|
INNER JOIN user u ON u.id_user = c.id_user
|
|
WHERE c.type = 'DEBIT'
|
|
GROUP BY u.id_user) debits ON credits.id_user = debits.id_user HAVING credit_left > {$creditMoreThan}
|
|
ORDER BY credit_left DESC ";
|
|
$results = c::db()->get( $query );
|
|
$credits = array();
|
|
foreach ( $results as $result ) {
|
|
$result->user = Crunchbutton_User::o( $result->id_user );
|
|
$giftcards = Crunchbutton_Promo::byIdUser( $result->id_user );
|
|
$result->giftcards = $giftcards->count();
|
|
$credits[] = $result;
|
|
}
|
|
return $results;
|
|
}
|
|
|
|
public function antifraudByPhone( $creditMoreThan = 10 ){
|
|
$query = "SELECT (credit - COALESCE( debits.debit, 0)) AS credit_left,
|
|
credits.credit,
|
|
COALESCE( debits.debit, 0) AS debit,
|
|
credits.phone
|
|
FROM
|
|
(SELECT SUM(c.value) AS credit,
|
|
u.phone
|
|
FROM credit c
|
|
INNER JOIN user u ON u.id_user = c.id_user
|
|
WHERE c.type = 'CREDIT'
|
|
AND u.phone IS NOT NULL
|
|
GROUP BY u.phone HAVING credit > {$creditMoreThan}) credits
|
|
INNER JOIN
|
|
(SELECT SUM(c.value) AS debit,
|
|
u.phone
|
|
FROM credit c
|
|
INNER JOIN user u ON u.id_user = c.id_user
|
|
WHERE c.type = 'DEBIT'
|
|
AND u.phone IS NOT NULL
|
|
GROUP BY u.phone) debits ON credits.phone = debits.phone HAVING credit_left > {$creditMoreThan}
|
|
ORDER BY credit_left DESC";
|
|
$results = c::db()->get( $query );
|
|
$credits = array();
|
|
foreach ( $results as $result ) {
|
|
$result->user = Crunchbutton_User::byPhone( $result->phone );
|
|
$giftcards = Crunchbutton_Promo::byPhone( $result->phone );
|
|
$result->giftcards = $giftcards->count();
|
|
$credits[] = $result;
|
|
}
|
|
return $results;
|
|
}
|
|
|
|
public function creditsByIdUser( $id_user ){
|
|
$query = "SELECT credits.credit,
|
|
debits.debit,
|
|
(credit - debit) AS credit_left
|
|
FROM
|
|
(SELECT SUM(value) AS credit
|
|
FROM credit c
|
|
INNER JOIN user u ON u.id_user = c.id_user
|
|
WHERE TYPE = 'CREDIT'
|
|
AND u.id_user = '{$id_user}') credits,
|
|
(SELECT SUM(value) AS debit
|
|
FROM credit c
|
|
INNER JOIN user u ON u.id_user = c.id_user
|
|
WHERE TYPE = 'DEBIT'
|
|
AND u.id_user = '{$id_user}') debits";
|
|
$results = c::db()->get( $query );
|
|
return $results->get(0);
|
|
}
|
|
|
|
public function creditsByPhone( $phone ){
|
|
$query = "SELECT credits.credit,
|
|
debits.debit,
|
|
(credit - debit) AS credit_left
|
|
FROM
|
|
(SELECT SUM(value) AS credit
|
|
FROM credit c
|
|
INNER JOIN user u ON u.id_user = c.id_user
|
|
WHERE TYPE = 'CREDIT'
|
|
AND u.phone = '{$phone}') credits,
|
|
(SELECT SUM(value) AS debit
|
|
FROM credit c
|
|
INNER JOIN user u ON u.id_user = c.id_user
|
|
WHERE TYPE = 'DEBIT'
|
|
AND u.phone = '{$phone}') debits";
|
|
$results = c::db()->get( $query );
|
|
return $results->get(0);
|
|
}
|
|
|
|
public function user() {
|
|
return User::o($this->id_user);
|
|
}
|
|
|
|
public function userFROM() {
|
|
return User::o($this->id_user_from);
|
|
}
|
|
|
|
public function order() {
|
|
return Order::o($this->id_order);
|
|
}
|
|
|
|
public function order_reference(){
|
|
return Order::o($this->id_order_reference);
|
|
}
|
|
|
|
public function promo() {
|
|
return Promo::o($this->id_promo);
|
|
}
|
|
|
|
public function restaurant() {
|
|
return Restaurant::o($this->id_restaurant);
|
|
}
|
|
|
|
public function restaurant_paid_by() {
|
|
return Restaurant::o($this->id_restaurant_paid_by);
|
|
}
|
|
} |