Report how many first time user gift codes used per school per day #4466

This commit is contained in:
Pererinha 2015-01-23 12:28:54 -02:00
parent db16b52c2d
commit a8b314b9b9
8 changed files with 590 additions and 0 deletions

View File

@ -0,0 +1,44 @@
<?php
class Controller_Api_Report extends Crunchbutton_Controller_RestAccount {
public function init() {
if( !c::admin()->permission()->check( [ 'global' ] ) ){
$this->_error();
}
switch ( c::getPagePiece( 2 ) ) {
case 'first-time-user-gift-codes-used-per-school-per-day':
$this->_first_time_user_gift_codes_used_per_school_per_day();
break;
default:
$this->_error();
break;
}
}
private function _first_time_user_gift_codes_used_per_school_per_day(){
$start = $this->request()[ 'start' ];
$end = $this->request()[ 'end' ];
if( !$start || !$end ){
$this->_error();
}
$start = explode( '/' , $start );
$start = $start[ 2 ] . $start[ 0 ] . $start[ 1 ];
$end = explode( '/' , $end );
$end = $end[ 2 ] . $end[ 0 ] . $end[ 1 ];
echo json_encode( Crunchbutton_Report_FirstTimeUserGiftCodesUsedPerSchoolPerDay::report( $start, $end ) );exit;;
}
private function _error( $error = 'invalid request' ){
echo json_encode( [ 'error' => $error ] );
exit();
}
}

View File

@ -0,0 +1,55 @@
<?php
class Crunchbutton_Report_FirstTimeUserGiftCodesUsedPerSchoolPerDay extends Cana_Model {
public function report( $start, $end ){
$pattern = "SELECT c.name AS community,
SUM(1) AS users,
'%s' AS `day`
FROM `order` o
INNER JOIN
(SELECT SUM(1) orders,
phone
FROM `order` o
WHERE DATE_FORMAT(o.date, '%%Y%%m%%d') <= '%s'
GROUP BY o.phone
HAVING orders = 1) orders ON orders.phone = o.phone AND DATE_FORMAT( o.date, '%%Y%%m%%d' ) = '%s'
INNER JOIN
(SELECT o.id_order
FROM `order` o
INNER JOIN credit c ON c.id_order = o.id_order
AND c.type = 'DEBIT'
INNER JOIN credit giftcard ON giftcard.id_credit = c.id_credit_debited_from
AND giftcard.id_promo IS NOT NULL
AND giftcard.credit_type = 'cash'
AND c.credit_type = 'cash' WHERE DATE_FORMAT( o.date, '%%Y%%m%%d' ) = '%s'
) giftcard ON giftcard.id_order = o.id_order
INNER JOIN restaurant_community rc ON rc.id_restaurant = o.id_restaurant
INNER JOIN community c ON rc.id_community = c.id_community
GROUP BY c.name
ORDER BY c.name ASC";
$communities = [];
$days = [];
for( $i = $start; $i <= $end; $i++ ){
$date = strval( $i );
$query = sprintf( $pattern, $date, $date, $date, $date );
$results = c::db()->get( $query );
if( count( $results ) ){
$formatted_date = new DateTime( $date, new DateTimeZone( c::config()->timezone ) );
$formatted_date = $formatted_date->format( 'M jS Y' );
foreach( $results as $result ){
$community = $result->community;
$users = intval( $result->users );
$communities[] = [ 'users' => $users, 'day' => $formatted_date, 'community' => $community ];
$days[] = [ 'users' => $users, 'day' => $formatted_date, 'community' => $community ];
}
}
}
return [ 'days' => $days, 'communities' => $communities ];
}
public function __construct(){}
}

View File

@ -68,6 +68,7 @@
<script src="/assets/cockpit/js/controllers.marketing.js?v=<?=Deploy_Server::currentVersion()?>"></script>
<script src="/assets/cockpit/js/controllers.blast.js?v=<?=Deploy_Server::currentVersion()?>"></script>
<script src="/assets/cockpit/js/controllers.tv.js?v=<?=Deploy_Server::currentVersion()?>"></script>
<script src="/assets/cockpit/js/controllers.report.js?v=<?=Deploy_Server::currentVersion()?>"></script>
<!-- AngularJS Filters -->
<script src="/assets/js/filters.js?v=<?=Deploy_Server::currentVersion()?>"></script>
@ -111,4 +112,5 @@
<script src="/assets/cockpit/js/service.favico.js?v=<?=Deploy_Server::currentVersion()?>"></script>
<script src="/assets/cockpit/js/service.blast.js?v=<?=Deploy_Server::currentVersion()?>"></script>
<script src="/assets/cockpit/js/service.tv.js?v=<?=Deploy_Server::currentVersion()?>"></script>
<script src="/assets/cockpit/js/service.report.js?v=<?=Deploy_Server::currentVersion()?>"></script>
<script src="/assets/cockpit/js/angular-cached-resource.min.js?v=<?=Deploy_Server::currentVersion()?>"></script><!--Michal added 1-19-15-->

View File

@ -0,0 +1,91 @@
<div class="top-pad"></div>
<div class="content-padding">
<h1 class="title"><i class="fa fa-newspaper-o"></i>First time user gift codes used per school per day</h1>
<div class="divider"></div>
<navigation-back></navigation-back>
<form name="form" novalidate>
<ul ng-class="{'submitted':submitted}" class="ul-inputs box-content2">
<li class="li-input" ng-class="{'error':form.rangeStart.$invalid}">
<div class="label">Date start:</div>
<div class="input"><input type="date" name="rangeStart" ng-model="range.start" required placeholder=""></div>
<div class="box-error">
<small ng-show="form.rangeStart.$error.required">Required.</small>
<small ng-show="form.rangeStart.$error.date">Enter a valid start date!</small>
</div>
</li>
<li class="li-input" ng-class="{'error':form.rangeEnd.$invalid}">
<div class="label">Date end:</div>
<div class="input"><input type="date" name="rangeEnd" ng-model="range.end" required placeholder=""></div>
<div class="box-error">
<small ng-show="form.rangeEnd.$error.required">Required.</small>
<small ng-show="form.rangeEnd.$error.date">Enter a valid end date!</small>
</div>
</li>
<li class="li-input" ng-show="!isProcessing">
<button class="button save" ng-click="report();">Report</button>
</li>
<li class="li-input" ng-show="isProcessing">
<span><i class="fa fa-circle-o-notch fa-spin"></i> Processing</span>
</li>
</ul>
</form>
<div ng-if="result">
<h2 class="title">
<span>By Community</span>
</h2>
<table class="tb-grid tb-zebra">
<thead>
<tr>
<td>Community</td>
<td>Day</td>
<td>Users</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="c in result.communities">
<td>{{c.community}}</td>
<td>{{c.day}}</td>
<td>{{c.users}}</td>
</tr>
</tbody>
</table>
<h2 class="title">
<span>By Day</span>
</h2>
<table class="tb-grid tb-zebra">
<thead>
<tr>
<td>Community</td>
<td>Day</td>
<td>Users</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="d in result.communities">
<td>{{d.community}}</td>
<td>{{d.day}}</td>
<td>{{d.users}}</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,15 @@
<div class="top-pad"></div>
<div class="content-padding">
<h1 class="title"><i class="fa fa-newspaper-o"></i>Reports</h1>
<div class="divider"></div>
<navigation-back></navigation-back>
<div class="box-content2 box-content-table">
<table>
<tr><td><a href="/report/first-time-users-gift-card">First time user gift codes used per school per day</a></td></tr>
</table>
</div>
</div>

View File

@ -9,6 +9,7 @@
<tr><td><a href="/support/phone">Make a call / Send SMS</a></td></tr>
<tr><td><a href="/blast">Blasts</a></td></tr>
<tr><td><a href="/marketing/outgoing">Marketing: Outgoing Emails/Texts</a></td></tr>
<tr><td><a href="/reports">Reports</a></td></tr>
</table>
</div>

View File

@ -0,0 +1,363 @@
NGApp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/reports', {
action: 'tools',
controller: 'ReportsCtrl',
templateUrl: 'assets/view/report.html',
reloadOnSearch: false
})
.when('/report/first-time-users-gift-card', {
action: 'tools',
controller: 'ReportFirstTimeUserGiftCodesUsedPerSchoolPerDayCtrl',
templateUrl: 'assets/view/report-first-time-users-gift-card.html'
})
}]);
NGApp.controller( 'ReportsCtrl', function(){} );
NGApp.controller( 'ReportFirstTimeUserGiftCodesUsedPerSchoolPerDayCtrl', function ( $scope, $filter, ReportService ) {
$scope.range = {};
var start = new Date();
start.setDate( start.getDate() - 14 );
$scope.range.start = start;
var end = new Date();
end.setDate( end.getDate() - 1 );
$scope.range.end = end;
$scope.result = null;
$scope.report = function(){
$scope.result = false;
if( $scope.form.$invalid ){
$scope.submitted = true;
return;
}
$scope.isProcessing = true;
var params = { 'start': $filter( 'date' )( $scope.range.start, 'MM/dd/yyyy'),
'end': $filter( 'date' )( $scope.range.end, 'MM/dd/yyyy') };
ReportService.first_time_user_gift_codes_used_per_school_per_day( params, function( json ){
console.log('json',json);
$scope.isProcessing = false;
$scope.result = json;
} );
}
} );
NGApp.controller( 'PexCardIdCtrl', function ( $scope, $routeParams, $route, PexCardService, DriverOnboardingService ) {
$scope.submitted = false;
$scope.isSearching = false;
$scope.status = PexCardService.status;
$scope._id_admin = false;
$scope.search = function() {
$scope.card = null;
if( $scope.isSearching ){
return;
}
if( $scope && $scope.form && $scope.form.$invalid ){
$scope.submitted = true;
$scope.isSearching = false;
return;
}
$scope.isSearching = true;
PexCardService.pex_id( $scope.crunchbutton_card_id,
function( json ){
$scope.isSearching = false;
$scope.submitted = false;
if( json.id ){
$scope.card = json;
if( $scope._id_admin ){
$scope.card.id_admin = $scope._id_admin;
}
console.log('$scope._id_admin',$scope._id_admin);
console.log('$scope.card',$scope.card);
} else {
$scope.flash.setMessage( json.error, 'error' );
$scope.crunchbutton_card_id = '';
}
}
);
};
$scope.payinfo = function(){
if( $scope.card.admin_login ){
$scope.navigation.link( '/staff/' + $scope.card.admin_login + '/payinfo' );
}
}
$scope.remove_assignment = function(){
if( confirm( 'Confirm remove assignment?' ) ){
PexCardService.admin_pexcard_remove( $scope.card.id, function( json ){
if( json.success ){
$scope.card.id_admin = null;
$scope.card.admin_name = null;
$scope.card.admin_login = null;
$scope.flash.setMessage( 'Driver assigned removed!', 'success' );
} else {
$scope.flash.setMessage( 'Error removing assignment!', 'error' );
}
} );
}
}
$scope.open_card = function( id_card ){
change_card_status( id_card, PexCardService.status.OPEN );
}
$scope.block_card = function( id_card ){
change_card_status( id_card, PexCardService.status.BLOCKED );
}
var change_card_status = function( id_card, status ){
if( confirm( 'Confirm change card status to ' + status + '?' ) ){
PexCardService.pex_change_card_status( { id_card: id_card, status: status },
function( json ){
if( json.id ){
$scope.card = json;
$scope.flash.setMessage( 'Card status changed to ' + status, 'success' );
} else {
$scope.flash.setMessage( json.error, 'error' );
}
}
);
}
}
$scope.assign = function(){
if( $scope.isSaving ){
return;
}
if( $scope.formAssign.$invalid ){
$scope.assignedSubmitted = true;
$scope.isSaving = false;
return;
}
var last_four = $scope.card.cards[ 0 ].cardNumber;
var data = { 'id_pexcard': $scope.card.id, 'id_admin': $scope.card.id_admin, 'card_serial': $scope.card.lastName, 'last_four': last_four };
PexCardService.admin_pexcard( data, function( json ){
$scope.isSaving = false;
if( json.success ){
$scope.card.admin_name = json.success.name;
$scope.card.admin_login = json.success.login;
$scope.flash.setMessage( 'Driver assigned!', 'success' );
} else {
$scope.flash.setMessage( 'Error assigning driver!', 'error' );
}
} );
}
DriverOnboardingService.pexcard( function( json ){ $scope.drivers = json; } );
if( $routeParams.id ){
if( $route.current.driver ){
setTimeout( function() {
$scope._id_admin = parseInt( $routeParams.id );
console.log('$scope._id_admin',$scope._id_admin);
}, 50 );
} else {
setTimeout( function() {
$scope.crunchbutton_card_id = parseInt( $routeParams.id );
App.rootScope.$safeApply();
$scope.search();
}, 500 );
}
}
} );
NGApp.controller('PexCardLogViewCtrl', function ($scope, $routeParams, PexCardService) {
$scope.loading = true;
PexCardService.action( $routeParams.id, function( action ){
$scope.action = action.success;
$scope.loading = false;
} );
} );
NGApp.controller('PexConfigCtrl', function ($scope, PexCardService) {
$scope.yesNo = PexCardService.yesNo();
$scope.business = { 'serial': '' };
$scope.test = { 'serial': '' };
var load = function(){
PexCardService.config.load( function( json ){
if( !json.error ){
$scope.config = json;
$scope.business.cards = json.cards.business;
$scope.test.cards = json.cards.test;
$scope.ready = true;
}
} );
}
$scope.add_business = function(){
if( $scope.idAdding ){
return;
}
if( $scope.formBusiness.$invalid ){
App.alert( 'Please fill in all required fields' );
$scope.businessSubmitted = true;
return;
}
$scope.idAdding = true;
PexCardService.config.add_business( { 'serial' : $scope.business.serial }, function( data ){
$scope.idAdding = false;
if( data.error ){
App.alert( data.error);
return;
} else {
$scope.business.serial = '';
$scope.business.cards = data.cards.business;
$scope.saved = true;
$scope.flash.setMessage( 'Business card addedd!' );
}
} );
}
$scope.remove_business = function( id_config ){
if( confirm( 'Confirm remove the Business Card?' ) ){
PexCardService.config.remove_business( { 'id_config' : id_config }, function( data ){
if( data.error ){
App.alert( data.error);
return;
} else {
$scope.business.cards = data.cards.business;
$scope.flash.setMessage( 'Business card removed!' );
}
} );
}
}
$scope.add_test = function(){
if( $scope.idAdding ){
return;
}
if( $scope.formTest.$invalid ){
App.alert( 'Please fill in all required fields' );
$scope.testSubmitted = true;
return;
}
$scope.idAdding = true;
console.log('$scope.test',$scope.test);
PexCardService.config.add_test( { 'serial' : $scope.test.serial }, function( data ){
$scope.idAdding = false;
if( data.error ){
App.alert( data.error);
return;
} else {
$scope.test.serial = '';
$scope.test.cards = data.cards.test;
$scope.saved = true;
$scope.flash.setMessage( 'Test card addedd!' );
}
} );
}
$scope.remove_test = function( id_config ){
if( confirm( 'Confirm remove the Test Card?' ) ){
PexCardService.config.remove_test( { 'id_config' : id_config }, function( data ){
if( data.error ){
App.alert( data.error);
return;
} else {
$scope.test.cards = data.cards.test;
$scope.flash.setMessage( 'Test card removed!' );
}
} );
}
}
$scope.save = function(){
if( $scope.form.$invalid ){
App.alert( 'Please fill in all required fields' );
$scope.submitted = true;
return;
}
$scope.isSaving = true;
PexCardService.config.save( $scope.config, function( data ){
$scope.isSaving = false;
if( data.error ){
App.alert( data.error);
return;
} else {
$scope.basicInfo = data;
$scope.saved = true;
$scope.flash.setMessage( 'Information saved!' );
setTimeout( function() { $scope.saved = false; }, 1500 );
}
} );
}
if( $scope.account.isLoggedIn() ){
load();
}
} );
NGApp.controller('PexCardLogCtrl', function ($scope, PexCardService, ViewListService) {
angular.extend( $scope, ViewListService );
$scope.view({
scope: $scope,
watch: {
search: '',
status: 'all',
type: 'all',
_action: 'all'
},
update: function() {
PexCardService.logs($scope.query, function(d) {
$scope.logs = d.results;
$scope.complete(d);
});
}
});
});
NGApp.controller('PexCardCardLogCtrl', function ($scope, PexCardService, ViewListService) {
angular.extend( $scope, ViewListService );
$scope.view({
scope: $scope,
watch: {
search: '',
type: 'card_assign',
},
update: function() {
PexCardService.cardlog($scope.query, function(d) {
$scope.logs = d.results;
$scope.complete(d);
});
}
});
});

View File

@ -0,0 +1,19 @@
NGApp.factory( 'ReportService', function( $resource, $http, $routeParams ) {
var service = { };
var report = $resource( App.service + 'report/:action/', { action: '@action' }, {
'first_time_user_gift_codes_used_per_school_per_day' : { 'method': 'POST', params : { action: 'first-time-user-gift-codes-used-per-school-per-day' } },
} );
service.first_time_user_gift_codes_used_per_school_per_day = function( params, callback ){
report.first_time_user_gift_codes_used_per_school_per_day( params, function( data ){
console.log('data',data);
callback( data );
} );
}
return service;
} );