瀏覽代碼

Merge branch 'feature-profilechilds' into beta

beta
Daniel 3 年之前
父節點
當前提交
ddbbad283d
共有 20 個檔案被更改,包括 455 行新增56 行删除
  1. +5
    -1
      .docker/Dockerfile
  2. +3
    -1
      README.md
  3. +2
    -1
      src/client/app/js/app/core/Dict.js
  4. +51
    -2
      src/client/manager/js/app/components/appointments/AppointmentSelectTable.js
  5. +2
    -0
      src/client/manager/js/app/components/appointments/appointment-select-table.html
  6. +9
    -0
      src/client/manager/js/app/components/contract/ContractAppointmentAssignDualList.js
  7. +30
    -2
      src/client/manager/js/app/components/contract/ContractUnchargedMemberDataTable.js
  8. +8
    -2
      src/client/manager/js/app/components/contract/contract-uncharged-member-data-table.html
  9. +1
    -1
      src/client/manager/js/app/components/settings/AccessDataTable.js
  10. +2
    -0
      src/client/manager/js/app/views/appointments/AppointmentList.js
  11. +50
    -36
      src/client/manager/js/app/views/contract/ContractCharging.js
  12. +68
    -5
      src/client/manager/js/app/views/contract/ContractEdit.js
  13. +52
    -0
      src/client/manager/js/app/views/contract/contract-edit.html
  14. +43
    -0
      src/client/manager/js/app/views/contract/contract-master-data.html
  15. +3
    -1
      src/server/server/config/boot_local.php
  16. +27
    -1
      src/server/server/control/TB_Server_Control_Contract.php
  17. +10
    -1
      src/server/server/control/TB_Server_Control_Team.php
  18. +80
    -0
      src/server/server/job/TB_Server_Job_DailyDbBackup.php
  19. +3
    -1
      src/server/shared/ent/teamdata/TB_Shared_Ent_TeamData_Appointment.php
  20. +6
    -1
      src/server/shared/ent/teamdata/TB_Shared_Ent_TeamData_Contract.php

+ 5
- 1
.docker/Dockerfile 查看文件

@@ -12,13 +12,17 @@ RUN apt-get install -y \
libjpeg62-turbo-dev \
libpng-dev \
libicu-dev \
libzip-dev \
zip \
&& docker-php-ext-install -j$(nproc) iconv \
&& docker-php-ext-configure gd --with-jpeg=/usr/include/ --with-freetype=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install -j$(nproc) intl \
&& docker-php-ext-install -j$(nproc) pdo_mysql
&& docker-php-ext-install -j$(nproc) pdo_mysql \
&& docker-php-ext-install zip

RUN apt-get install -y git zip
RUN apt-get install mariadb-client -y

RUN apt install nano



+ 3
- 1
README.md 查看文件

@@ -6,4 +6,6 @@
- info@coaching4dogs.xx (kein Admin-Account)
- benny@probuddy.de
- timo@tbuddy.de
- tretslag@gmail.com
- tretslag@gmail.com
- `docker exec -it pb-php /bin/bash`
- SELECT * FROM profile WHERE JSON_CONTAINS( `teams_js`, '{"team_id":"75"}' );

+ 2
- 1
src/client/app/js/app/core/Dict.js 查看文件

@@ -541,7 +541,8 @@ app.core.Dict = {
"APPOINTMENT_CATEGORIES_MISSING_FOR_ADMIN" : "Deinem Gruppenprofil wurden keine Kategorien zugewiesen. Bitte benachrichtige den Gruppeninhaber.",
"NOTE_NO_SERIAL_APPOINTMENT_EDITING_AFTER_PUBLISHING" : "Hinweis: Serientermine können nach ihrer Veröffentlichung nur noch einzelnd bearbeitet werden.",
"STATS_REPORTING" : 'Reporting',
'STATS_PLANNING' : 'Planung'
'STATS_PLANNING' : 'Planung',
"DO_YOU_REALLY_WANT_TO_DELETE_THIS_CONTRACT" : "Möchtest Du diesen Vertrag wirklich löschen?",
},
"en" : {
}

+ 51
- 2
src/client/manager/js/app/components/appointments/AppointmentSelectTable.js 查看文件

@@ -5,9 +5,33 @@ const AppointmentSelectTable = {
var app = this.app,
$container = $( this.container );
this.render( { apps: appointments.getAll(), activeGroup : this.app.user.getActiveGroup() } );
let date = new Date();
let strFrom = '';
date.setMonth(date.getMonth() - 3);
let dd = String(date.getDate()).padStart(2, '0');
let mm = String(date.getMonth() + 1).padStart(2, '0'); //January is 0!
let yyyy = date.getFullYear();
strFrom = yyyy + '-' + mm + '-' + dd;
$container.find( '.datatable' ).DataTable( {
date = new Date();
let strTo = '';
date.setMonth(date.getMonth() + 3);
dd = String(date.getDate()).padStart(2, '0');
mm = String(date.getMonth() + 1).padStart(2, '0'); //January is 0!
yyyy = date.getFullYear();
strTo = yyyy + '-' + mm + '-' + dd;
let appointmentItems = appointments.getAll();
this.render(
{ apps: appointmentItems,
activeGroup : this.app.user.getActiveGroup(),
strFrom: strFrom,
strTo: strTo
}
);
let table = $container.find( '.datatable' ).DataTable( {
pageLength: 50,
responsive: true,
dom: '<"html5buttons"B>lTfgitp',
@@ -78,6 +102,31 @@ const AppointmentSelectTable = {
app.openInApp( '/#/appointment/' + $( this ).attr( 'data-appointment-id' ) + '/chat' );
e.stopPropagation();
});
$('input.dateStart').on('change', function() {
table.draw();
});
$('input.dateEnd').on('change', function() {
table.draw();
});
$.fn.dataTable.ext.search.push(
function(settings, searchData, index, rowData, counter) {
const dateFrom = $('input.dateStart').val();
const dateTo = $('input.dateEnd').val();
const item = appointmentItems[index];
const startDate = item['start_dt'];
const strStartDate = startDate.date.substring(0,10);
if (strStartDate >= dateFrom && strStartDate <= dateTo) {
return true;
}
return false;
}
);
// Initial drawing needed to filter by date interval
table.draw();
},
getSelectedIds : function()


+ 2
- 0
src/client/manager/js/app/components/appointments/appointment-select-table.html 查看文件

@@ -1,4 +1,6 @@
<div class="table-responsive">
<label style="margin-left: 15px">von:<input type="date" style="margin-left: 12px;margin-right: 5px;" class="dateStart" name="search-start" value="<%= strFrom %>"></label>
<label>bis:<input type="date" style="margin-left: 12px;margin-right: 5px;"class="dateEnd" name="search-end" value="<%= strTo %>"></label>
<table class="table table-striped table-bordered table-hover datatable" >
<thead>
<tr>


+ 9
- 0
src/client/manager/js/app/components/contract/ContractAppointmentAssignDualList.js 查看文件

@@ -12,6 +12,11 @@ const ContractAppointmentAssignDualList = {
self.contracts = props.get( 'contracts');
self.attendedAppointments = props.get( 'attendedAppointments' );
self.childObj = {};
for (const prop in profile.child_profile_js) {
self.childObj[profile.child_profile_js[prop]['id']] = profile.child_profile_js[prop]['name'];
}
this.render(
{
profile : profile,
@@ -131,6 +136,10 @@ const ContractAppointmentAssignDualList = {
}
aSubject += a.subject + ', ' + moment( a.start_dt ).format( 'DD.MM.YYYY' );
if (a.attendee_child_id !== null) {
aSubject += ' (' + self.childObj[a.attendee_child_id] + ')';
}
if ( self.selectedContractId && self.attendedAppointments[ aai ].contractId == self.selectedContractId )
{
$select.append(


+ 30
- 2
src/client/manager/js/app/components/contract/ContractUnchargedMemberDataTable.js 查看文件

@@ -4,11 +4,13 @@ const ContractUnchargedMemberDataTable = {
{
var app = this.app,
groupId = props.get( 'groupId' ),
items = props.get( 'unchargedItems' ),
$container = $( this.container );
this.render( { ui: props.get( 'unchargedItems' ), activeGroup : groupId } );
this.render( { ui: items, activeGroup : groupId } );
$container.find( '.datatable' ).DataTable( {
let table = $container.find( '.datatable' ).DataTable( {
pageLength: 50,
responsive: true,
dom: '<"html5buttons"B>lTfgitp',
@@ -49,6 +51,32 @@ const ContractUnchargedMemberDataTable = {
{
app.redirect( '/contract/charge-appointment/' + groupId + '/' + $( e.currentTarget ).attr( 'data-member-id' ) );
});
$('input.filterContract').on('change', function() {
table.draw();
});
$('input.filterOpenClaim').on('change', function() {
table.draw();
});
$.fn.dataTable.ext.search.push(
function(settings, searchData, index, rowData, counter) {
const contractChecked = $('.filterContract:checked').length === 1;
const openClaimChecked = $('.filterOpenClaim:checked').length === 1;
const item = items[index];
if (contractChecked && openClaimChecked) {
return item['hasActiveContract'] === false && parseInt(item['count']) !== 0;
}
if (contractChecked) {
return item['hasActiveContract'] === false;
}
if (openClaimChecked) {
return parseInt(item['count']) !== 0;
}
return true;
}
);
},
destroy : function()


+ 8
- 2
src/client/manager/js/app/components/contract/contract-uncharged-member-data-table.html 查看文件

@@ -1,4 +1,6 @@
<div class="table-responsive">
<label><input type="checkbox" style="margin-right: 5px;" class="filterContract" value="Active"/>ohne aktiven Vertag</label>
<label><input type="checkbox" style="margin-left: 12px;margin-right: 5px;" class="filterOpenClaim" value="Active"/>nur offene Verrechnungen</label>
<table class="table table-striped table-bordered table-hover datatable" >
<thead>
<tr>
@@ -8,6 +10,7 @@
<th>PLZ</th>
<th>Stadt</th>
<th>Offene Verrechnungen</th>
<th>Aktiver Vertrag vorhanden</th>
</tr>
</thead>
<tbody>
@@ -19,7 +22,7 @@
<%= ui[ i ].member ? ui[ i ].member.id : '-' %>
</td>
<td>
<%= ui[ i ].member ? ui[ i ].member.getName() : '[gelöscht]' %>
<%= ui[ i ].member ? ui[ i ].member.getName() : '[gelöscht - nicht mehr Mitglied der Gruppe]' %>
</td>
<td>
<%= ui[ i ].member && ui[ i ].member.street ? ui[ i ].member.street : '---' %>
@@ -30,9 +33,12 @@
<td>
<%= ui[ i ].member && ui[ i ].member.city ? ui[ i ].member.city : '---' %>
</td>
<td class="text-center">
<td>
<%= ui[ i ].count %>
</td>
<td>
<%= ui[ i ].hasActiveContract ? 'ja' : 'nein' %>
</td>
</tr>
<% } %>
</tbody>


+ 1
- 1
src/client/manager/js/app/components/settings/AccessDataTable.js 查看文件

@@ -36,7 +36,7 @@ const AccessDataTable = {
},
},
buttons: [
{ extend: 'copy'},
{extend: 'copy'},
{extend: 'csv'},
{extend: 'excel', title: 'Mitgliederliste'},
{extend: 'pdf', title: 'Mitgliederliste'},


+ 2
- 0
src/client/manager/js/app/views/appointments/AppointmentList.js 查看文件

@@ -59,6 +59,8 @@ const AppointmentList = {
}
}
let compAst = this.createComponent(
'appointment-select-table',
$container.find( '[f-id="container-appointment-data-table"]' ).first().get( 0 ),


+ 50
- 36
src/client/manager/js/app/views/contract/ContractCharging.js 查看文件

@@ -16,6 +16,7 @@ const ContractCharging = {
app = this.app,
members = [],
groupId = p.get( 'groupId' ),
profileIdsWithActiveContract = [],
self = this;
function getMemberById( mId )
@@ -30,7 +31,6 @@ const ContractCharging = {
break;
}
}
return m;
}
@@ -56,49 +56,63 @@ const ContractCharging = {
app.rpc.call(
'Contract',
'getUnchargedProfileIds',
'getList',
{
teamId : groupId
teamId : groupId,
state : 'active'
},
function( res )
{
let unchargedItems = [],
memberIdsInList = [];
if ( res && res.hasOwnProperty( 'data' ) && res.data.hasOwnProperty( 'unchargedProfileIds' ) )
{
const up = res.data.unchargedProfileIds;
for( let upi = 0; upi < up.length; upi++ )
{
memberIdsInList.push( +up[ upi ].profile_id );
unchargedItems.push({
member : getMemberById( up[ upi ].profile_id ),
count : up[ upi ].cnt
});
function( res ) {
if (res && res.hasOwnProperty('data') && res.data.hasOwnProperty('contractData')) {
const cs = res.data.contractData;
for (let ci = 0; ci < cs.length; ci++) {
profileIdsWithActiveContract[cs[ci]['profile_id']] = 1;
}
}
for ( let mi = 0; mi < members.length; mi++ )
{
if ( -1 === memberIdsInList.indexOf( +members[ mi ].id ) )
app.rpc.call(
'Contract',
'getUnchargedProfileIds',
{
unchargedItems.push({
member : members[ mi ],
count : 0
});
}
}
teamId: groupId
},
function (res) {
let unchargedItems = [],
memberIdsInList = [];
if (res && res.hasOwnProperty('data') && res.data.hasOwnProperty('unchargedProfileIds')) {
const up = res.data.unchargedProfileIds;
for (let upi = 0; upi < up.length; upi++) {
memberIdsInList.push(+up[upi].profile_id);
unchargedItems.push({
member: getMemberById(up[upi].profile_id),
count: up[upi].cnt,
hasActiveContract: profileIdsWithActiveContract.hasOwnProperty(up[upi].profile_id)
});
}
}
let st = self.createComponent(
'contract-uncharged-member-data-table',
$container.find( '[f-id="container-contract-uncharged-member-table"]' ).first().get( 0 ),
{
unchargedItems : unchargedItems,
groupId : groupId
}
);
for (let mi = 0; mi < members.length; mi++) {
if (-1 === memberIdsInList.indexOf(+members[mi].id)) {
unchargedItems.push({
member: members[mi],
count: 0,
hasActiveContract: -1 !== profileIdsWithActiveContract.indexOf(+members[mi].id)
});
}
}
$container.find( '.sk-loading' ).toggleClass( 'sk-loading' );
}.bind ( this )
let st = self.createComponent(
'contract-uncharged-member-data-table',
$container.find('[f-id="container-contract-uncharged-member-table"]').first().get(0),
{
unchargedItems: unchargedItems,
groupId: groupId
}
);
$container.find('.sk-loading').toggleClass('sk-loading');
}.bind(this)
);
}
);
}
}


+ 68
- 5
src/client/manager/js/app/views/contract/ContractEdit.js 查看文件

@@ -21,8 +21,7 @@ const ContractEdit = {
self = this;
self.contract = null;
this.render( { groupId : groupId } );
self.contractIsDeletable = false;
app.rpc.call(
'Contract',
@@ -32,11 +31,16 @@ const ContractEdit = {
},
function( res )
{
if ( res && res.hasOwnProperty( 'data' ) && res.data.hasOwnProperty( 'contractData' ) )
if ( res && res.hasOwnProperty( 'data' ))
{
self.contract = self.createInstance( 'Contract', res.data.contractData );
if ( res.data.hasOwnProperty( 'contractData' ) ) {
self.contract = self.createInstance( 'Contract', res.data.contractData );
}
if ( res.data.hasOwnProperty( 'contractIsDeletable' ) ) {
self.contractIsDeletable = res.data.contractIsDeletable;
}
}
this.render( { groupId : groupId, contractIsDeletable: self.contractIsDeletable } );
const $compContractForm = self.createComponent(
'contract-form',
$container.find( '[f-id="container-contract-form"]' ).first().get( 0 ),
@@ -89,10 +93,69 @@ const ContractEdit = {
}
});
if (self.contractIsDeletable) {
$container.find( '[data-id="btnDeleteContract"]').click( function()
{
let $modalRoot = $container.find( '[data-id="modal-confirm-delete-contract"]' ).first();
$modalRoot.find( '[data-id="section-confirm-delete-contract"]' ).first().show();
$modalRoot.find( '[data-id="section-loader"]' ).first().hide();
$modalRoot.on( 'shown.bs.modal', function()
{
$modalRoot.find( '[data-id="btnDelete"]' ).first().off( "click" );
$modalRoot.find( '[data-id="btnDelete"]' ).first().click( function()
{
$(this).off( "click" );
$modalRoot.find( '[data-id="section-confirm-delete-contract"]' ).first().hide();
$modalRoot.find( '[data-id="section-loader"]' ).first().show();
app.rpc.call(
'Contract',
'delete',
{
contractId : contractId
},
function( resp )
{
if ( resp && resp.hasOwnProperty( 'code' ) && resp.code == 200 )
{
app.UI.toastSuccess( 'Vertrag wurde erfolgreich gelöscht.', 'Vertrag gelöscht' );
if ( redirectPath )
{
app.redirect( redirectPath );
}
else
{
app.redirect( 'contract/list/' + groupId );
}
}
else
{
app.UI.toastError( 'Der Vertrag konnte nicht gelöscht werden, ' +
'da er entweder mindestens eine verknüpfte Verrechnung oder bereits ' +
'eine Einzahlung stattgefunden hat',
'Fehler' );
}
$modalRoot.modal( 'hide' );
}
);
});
});
$modalRoot.on( 'hidden.bs.modal', function()
{
$modalRoot.modal( 'dispose' );
});
$modalRoot.modal( 'show' );
}
);
}
$container.find( '.sk-loading' ).toggleClass( 'sk-loading' );
}.bind ( this )
);
},
destroy : function()


+ 52
- 0
src/client/manager/js/app/views/contract/contract-edit.html 查看文件

@@ -40,10 +40,62 @@
href="javascript:history.back()">
Abbrechen
</a>
<% if ( true === contractIsDeletable ) { %>
<button type="button"
class="btn btn-danger"
data-id="btnDeleteContract">
Löschen
</button>
<% } %>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal inmodal fade"
data-id="modal-confirm-delete-contract"
tabindex="-1"
role="dialog"
aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button"
class="close"
data-dismiss="modal">
<span aria-hidden="true">&times;</span><span class="sr-only">Close</span>
</button>
<h4 class="modal-title">Vertrag löschen</h4>
</div>
<div class="modal-body">
<section data-id="section-confirm-delete-contract"
style="display: none">
<h5>Vertrag löschen?</h5>
<p>
Möchten Sie den Vertrag wirklich löschen?
</p>
</section>
<section data-id="section-loader"
style="display: none">
<div style="height: 200px; padding-top: 70px">
<div class="sk-spinner sk-spinner-double-bounce">
<div class="sk-double-bounce1"></div>
<div class="sk-double-bounce2"></div>
</div>
</div>
</section>
</div>
<div class="modal-footer">
<button type="button"
class="btn btn-white"
data-dismiss="modal">Abbrechen</button>
<button type="button"
data-id="btnDelete"
class="btn btn-danger">Ja, löschen</button>
</div>
</div>
</div>
</div>

+ 43
- 0
src/client/manager/js/app/views/contract/contract-master-data.html 查看文件

@@ -118,6 +118,49 @@
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">
BLZ, IBAN
</label>
<div class="col-sm-3">
<input type="text"
name="bank_code"
class="form-control"
value="<%= group.getContracteeData( 'bank_code' ) ? group.getContracteeData( 'bank_code' ) : '' %>"
placeholder="BLZ" />
</div>
<div class="col-sm-7">
<input type="text"
name="account_number"
class="form-control"
value="<%= group.getContracteeData( 'account_number' ) ? group.getContracteeData( 'account_number' ) : '' %>"
placeholder="IBAN" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">
Bankinstitut
</label>
<div class="col-sm-10">
<input type="text"
name="bank_name"
class="form-control"
value="<%= group.getContracteeData( 'bank_name' ) ? group.getContracteeData( 'bank_name' ) : '' %>"
placeholder="Bankinstitut" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">
PaypalMe
</label>
<div class="col-sm-10">
<input type="text"
name="paypal_me"
class="form-control"
value="<%= group.getContracteeData( 'paypal_me' ) ? group.getContracteeData( 'paypal_me' ) : '' %>"
placeholder="PaypalMe" />
</div>
</div>
<div class="hr-line-dashed"></div>
</form>
</div>


+ 3
- 1
src/server/server/config/boot_local.php 查看文件

@@ -21,7 +21,9 @@ Francis_Utils_Config::set( 'db.tbteamdata.pass', 'root' );
// Paths
Francis_Utils_Config::set( 'path.logfile', '/var/www/html/logs/tbserver-log.txt' );
Francis_Utils_Config::set( 'path.cron_logfile', '/var/www/html/logs/tbserver-cron-log.txt' );
Francis_Utils_Config::set( 'path.backup_folder', '/temp' );
Francis_Utils_Config::set( 'path.backup_folder', '/var/www/html/temp' );
Francis_Utils_Config::set( 'path.root', realpath( dirname( __FILE__ ) . '/../../../..' ) );
Francis_Core_Autoloader::attachLocator( new Francis_Core_Locator( 'TB', Francis_Utils_Config::get( 'path.root' ) . '/src/server' ) );
Francis_Utils_Config::set( 'path.server.controller', Francis_Utils_Config::get( 'path.root' ) . '/src/server/server/control' );


+ 27
- 1
src/server/server/control/TB_Server_Control_Contract.php 查看文件

@@ -151,7 +151,7 @@ class TB_Server_Control_Contract
{
$resp->addData( 'contractAppointments', [] );
}
$resp->addData('contractIsDeletable', $contract->isDeletable());
return $resp;
}
@@ -515,6 +515,32 @@ class TB_Server_Control_Contract
return $resp;
}
public static function delete( TB_Server_Core_RequestData $params )
{
$resp = new TB_Server_Core_Response();
$sessionProfile = TB_Server_Core_Session::get()->getProfile();
$contractId = $params->get('contractId' );
$contract = TB_Shared_Ent_TeamData_Contract::get( $contractId );
if ( NULL === $contract )
{
throw new \Exception( 'Contract not found.' );
}
if ( false === $sessionProfile->isAdminOfTeam( $contract->team_id ) && $sessionProfile->id != $contract->profile_id )
{
throw new \Exception('Profile is not allowed to delete contract');
}
if ( !$contract->isDeletable() )
{
throw new \Exception('Contract is not deletable');
}
$contract->delete();
return $resp;
}
public static function updateAttendances( TB_Server_Core_RequestData $params )
{
$resp = new TB_Server_Core_Response();


+ 10
- 1
src/server/server/control/TB_Server_Control_Team.php 查看文件

@@ -912,6 +912,11 @@ class TB_Server_Control_Team {
$cZipCode = $params->get( 'zip_code' );
$cCity = $params->get( 'city' );
$cCountry = $params->get( 'country' );
$cBankCode = $params->get( 'bank_code' );
$cAccountNumber = $params->get( 'account_number' );
$cBankName = $params->get( 'bank_name' );
$cPaypalMe = $params->get( 'paypal_me' );
if ( !$cName || !$cStreet || !$cZipCode || !$cCity || !$cCountry )
{
@@ -923,7 +928,11 @@ class TB_Server_Control_Team {
'street' => $cStreet,
'zip_code' => $cZipCode,
'city' => $cCity,
'country' => $cCountry
'country' => $cCountry,
'bank_code' => $cBankCode,
'account_number' => $cAccountNumber,
'bank_name' => $cBankName,
'paypal_me' => $cPaypalMe
);
$team->save();


+ 80
- 0
src/server/server/job/TB_Server_Job_DailyDbBackup.php 查看文件

@@ -0,0 +1,80 @@
<?php
/********************************************************************************
* (c)1337 aheadware.com - All rights reserved
********************************************************************************/
class TB_Server_Job_DailyDbBackup extends TB_Server_Job_Base
{
public function __construct( TB_Shared_Ent_TeamData_Job $jobEntity )
{
$this->entity = $jobEntity;
}
public function execute()
{
// Remove old DB dumps
$dayInSeconds = 60 * 60 * 24;
$pastDays = 7;
$dumpFile = Francis_Utils_Config::get( 'path.backup_folder' ) . '/dbdump';
while ( file_exists( $dumpFile . date( 'Y-m-d', ( time() - ( $pastDays * $dayInSeconds ) ) ) . '.zip' ) ) {
unlink( $dumpFile . date( 'Y-m-d', ( time() - ( $pastDays * $dayInSeconds ) ) ) . '.zip' );
$pastDays++;
}
// DB Core
$db_host = Francis_Utils_Config::get( 'db.tbcore.host' );
$db_user = Francis_Utils_Config::get( 'db.tbcore.user' );
$db_name = Francis_Utils_Config::get( 'db.tbcore.name' );
$db_passwd = Francis_Utils_Config::get( 'db.tbcore.pass' );
$sql_file = Francis_Utils_Config::get( 'path.backup_folder' ) . "/tbcore.sql";
//exec("mysql -u $db_name -p'$db_passwd' --allow-keywords --add-drop-table --complete-insert --quote-names --routines $db_name > $sql_file");
exec("mysqldump -h $db_host -u $db_user -p'$db_passwd' $db_name > $sql_file");
// DB Teamdata
$db_host = Francis_Utils_Config::get( 'db.tbteamdata.host' );
$db_user = Francis_Utils_Config::get( 'db.tbteamdata.user' );
$db_name = Francis_Utils_Config::get( 'db.tbteamdata.name' );
$db_passwd = Francis_Utils_Config::get( 'db.tbteamdata.pass' );
$sql_file = Francis_Utils_Config::get( 'path.backup_folder' ) . "/tbteamdata.sql";
exec("mysqldump -h $db_host -u $db_user -p'$db_passwd' $db_name > $sql_file");
//exec("mysql -u $db_name -p'$db_passwd' --allow-keywords --add-drop-table --complete-insert --quote-names --routines $db_name > $sql_file");
// Zip
$zipFilename = Francis_Utils_Config::get( 'path.backup_folder' ) . '/dbdump' . date( 'Y-m-d' ) . '.zip';
$zip = new ZipArchive();
if ( !$zip->open( $zipFilename, ZipArchive::CREATE ) ) {
TB_Server_Utils_Log::get()->log( "Cannot zip db dump." );
return;
}
$zip->addFile( Francis_Utils_Config::get( 'path.backup_folder' ) . '/tbcore.sql' , 'tbcore.sql' );
$zip->addFile( Francis_Utils_Config::get( 'path.backup_folder' ) . '/tbteamdata.sql' , 'tbteamdata.sql' );
$zip->close();
// Cleanup
$sql_file = Francis_Utils_Config::get( 'path.backup_folder' ) . "/tbcore.sql";
unlink( $sql_file );
$sql_file = Francis_Utils_Config::get( 'path.backup_folder' ) . "/tbteamdata.sql";
unlink( $sql_file );
echo 'bla';
}
public function onDone()
{
// Reset event to start the next day
$nowDt = new DateTime( 'now', new \DateTimeZone( "UTC" ) );
$nowDt->setTime( 2, 0, 0 );
$nowDt->modify( '+1 day' );
$this->entity->trigger_dt = $nowDt;
$this->entity->job_status = TB_Shared_Ent_TeamData_Job::JOB_STATUS_READY;
$this->entity->touch( 'job_status' );
$this->entity->save();
}
public static function getRefId()
{
return 'system-daily-db-backup';
}
}

+ 3
- 1
src/server/shared/ent/teamdata/TB_Shared_Ent_TeamData_Appointment.php 查看文件

@@ -250,6 +250,8 @@ class TB_Shared_Ent_TeamData_Appointment extends Francis_Db_Row
if ( false === $filterGetOld )
{
$sql .= "AND end_dt > UTC_TIMESTAMP() ";
} else {
$sql .= "AND end_dt > UTC_TIMESTAMP() - INTERVAL 1 MONTH ";
}
$sql .= "ORDER BY start_dt ASC";
$stmt = $dbh->prepare( $sql );
@@ -514,7 +516,7 @@ class TB_Shared_Ent_TeamData_Appointment extends Francis_Db_Row
public static function getTeamAppointmentsForAttendedProfileId( $teamId, $profileId )
{
$sql = 'SELECT a.id AS `attendee_id`, a.contract_id AS `attendee_contract_id`, app.* FROM `attendee` AS a ';
$sql = 'SELECT a.id AS `attendee_id`, a.contract_id AS `attendee_contract_id`, a.`profile_child_id` AS `attendee_child_id`, app.* FROM `attendee` AS a ';
$sql .= 'LEFT JOIN appointment AS `app` ON a.appointment_id = app.id ';
$sql .= 'WHERE ';
$sql .= 'app.team_id = :team_id AND a.profile_id = :profile_id AND ';


+ 6
- 1
src/server/shared/ent/teamdata/TB_Shared_Ent_TeamData_Contract.php 查看文件

@@ -168,7 +168,6 @@ class TB_Shared_Ent_TeamData_Contract extends Francis_Db_Row
$sql .= "AND app.state = 'open' ";
$sql .= 'AND app.start_dt < NOW() ';
$sql .= 'AND a.has_attended = "attended" AND a.contract_id IS NULL GROUP BY a.profile_id';
$dbh = self::getDbh();
$stmt = $dbh->prepare( $sql );
@@ -218,6 +217,12 @@ class TB_Shared_Ent_TeamData_Contract extends Francis_Db_Row
TB_Shared_Ent_TeamData_Attendee::removeContractId( $this->id );
}
public function isDeletable()
{
$attendees = TB_Shared_Ent_TeamData_Attendee::getAttendancesForContractId( $this->id );
return (int) $this->price_payed === 0 && count($attendees) === 0;
}
/**
* Return table name
*


Loading…
取消
儲存