Esempio n. 1
0
 public static function process($action = 'list', $id = null, $filters = array())
 {
     switch ($action) {
         case 'fulfill':
             $sql = "UPDATE invest_reward SET fulfilled = 1 WHERE invest = ?";
             if (Model\Invest::query($sql, array($id))) {
                 Message::Info(Text::get('admin-rewards-info-status-completed'));
             } else {
                 Message::Error(Text::get('admin-rewards-error-statuschage-fail'));
             }
             throw new Redirection('/admin/rewards');
             break;
         case 'unfill':
             $sql = "UPDATE invest_reward SET fulfilled = 0 WHERE invest = ?";
             if (Model\Invest::query($sql, array($id))) {
                 Message::Info(Text::get('admin-rewards-info-status-completed-pending'));
             } else {
                 message::Error('Ha fallado al desmarcar');
             }
             throw new Redirection('/admin/rewards');
             break;
     }
     // edicion
     if ($action == 'edit' && !empty($id)) {
         $invest = Model\Invest::get($id);
         $projectData = Model\Project::get($invest->project);
         $userData = Model\User::getMini($invest->user);
         $status = Model\Project::status();
         // si tratando post
         if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['update'])) {
             $errors = array();
             // la recompensa:
             $chosen = $_POST['selected_reward'];
             if (empty($chosen)) {
                 // renuncia a las recompensas, bien por el/ella!
                 $invest->rewards = array();
             } else {
                 $invest->rewards = array($chosen);
             }
             $invest->anonymous = $_POST['anonymous'];
             // dirección de envio para la recompensa
             // y datos fiscales por si fuera donativo
             $invest->address = (object) array('name' => $_POST['name'], 'nif' => $_POST['nif'], 'address' => $_POST['address'], 'zipcode' => $_POST['zipcode'], 'location' => $_POST['location'], 'country' => $_POST['country']);
             if ($invest->update($errors)) {
                 Message::Info(Text::get('admin-rewards-info-update'));
                 throw new Redirection('/admin/rewards');
             } else {
                 Message::Error('No se han actualizado correctamente los datos del aporte. ERROR: ' . implode(', ', $errors));
             }
         }
         return new View('view/admin/index.html.php', array('folder' => 'rewards', 'file' => 'edit', 'invest' => $invest, 'project' => $projectData, 'user' => $userData, 'status' => $status));
     }
     // listado de proyectos
     $projects = Model\Invest::projects();
     $status = array('nok' => Text::_("Pendiente"), 'ok' => Text::_("Cumplida"));
     // listado de aportes
     if ($filters['filtered'] == 'yes') {
         $list = Model\Project\Reward::getChossen($filters);
     } else {
         $list = array();
     }
     return new View('view/admin/index.html.php', array('folder' => 'rewards', 'file' => 'list', 'list' => $list, 'filters' => $filters, 'projects' => $projects, 'status' => $status));
 }
Esempio n. 2
0
            if ($social_reward->icon == 'other') {
                $social_rewards["social_reward-{$social_reward->id}"]['children']["social_reward-{$social_reward->id}-other-orig"] = array('type' => 'html', 'title' => Text::get('rewards-field-social_reward-other'), 'html' => $original->other);
                $social_rewards["social_reward-{$social_reward->id}"]['children']["social_reward-{$social_reward->id}-other"] = array('title' => '', 'type' => 'textbox', 'size' => 100, 'class' => 'inline other', 'value' => $social_reward->other, 'errors' => array(), 'ok' => array(), 'hint' => Text::get('tooltip-project-social_reward-icon-other'));
            }
            // el boton al final
            $social_rewards["social_reward-{$social_reward->id}"]['children']["social_reward-{$social_reward->id}-buttons"] = array('type' => 'group', 'class' => 'buttons', 'children' => array("social_reward-{$social_reward->id}-ok" => array('type' => 'submit', 'label' => Text::get('form-accept-button'), 'class' => 'inline ok')));
        } else {
            $social_rewards["social_reward-{$social_reward->id}"] = array('class' => 'reward social_reward', 'view' => 'view/dashboard/translates/rewards/reward.html.php', 'data' => array('reward' => $social_reward, 'licenses' => $this['licenses']));
        }
    }
}
if (!empty($project->individual_rewards)) {
    foreach ($project->individual_rewards as $individual_reward) {
        // a ver si es el que estamos editando o no
        if (!empty($this["individual_reward-{$individual_reward->id}-edit"])) {
            $original = \Goteo\Model\Project\Reward::get($individual_reward->id);
            // a este grupo le ponemos estilo de edicion
            $individual_rewards["individual_reward-{$individual_reward->id}"] = array('type' => 'group', 'class' => 'reward individual_reward editindividual_reward', 'children' => array("individual_reward-{$individual_reward->id}-reward-orig" => array('title' => Text::get('rewards-field-individual_reward-reward'), 'type' => 'html', 'html' => $original->reward), "individual_reward-{$individual_reward->id}-reward" => array('title' => '', 'type' => 'textbox', 'size' => 100, 'class' => 'inline', 'value' => $individual_reward->reward, 'errors' => array(), 'ok' => array(), 'hint' => Text::get('tooltip-project-individual_reward-reward')), "individual_reward-{$individual_reward->id}-description-orig" => array('type' => 'html', 'title' => Text::get('rewards-field-individual_reward-description'), 'html' => $original->description), "individual_reward-{$individual_reward->id}-description" => array('type' => 'textarea', 'title' => '', 'cols' => 100, 'rows' => 4, 'class' => 'inline reward-description', 'value' => $individual_reward->description, 'errors' => array(), 'ok' => array(), 'hint' => Text::get('tooltip-project-individual_reward-description'))));
            // añadir el campo otros
            if ($individual_reward->icon == 'other') {
                $individual_rewards["individual_reward-{$individual_reward->id}"]['children']["individual_reward-{$individual_reward->id}-other-orig"] = array('type' => 'html', 'title' => Text::get('rewards-field-individual_reward-other'), 'html' => $original->other);
                $individual_rewards["individual_reward-{$individual_reward->id}"]['children']["individual_reward-{$individual_reward->id}-other"] = array('title' => '', 'type' => 'textbox', 'size' => 100, 'class' => 'inline', 'value' => $individual_reward->other, 'errors' => array(), 'ok' => array(), 'hint' => Text::get('tooltip-project-individual_reward-icon-other'));
            }
            // el boton al final
            $individual_rewards["individual_reward-{$individual_reward->id}"]['children']["individual_reward-{$individual_reward->id}-buttons"] = array('type' => 'group', 'class' => 'buttons', 'children' => array("individual_reward-{$individual_reward->id}-ok" => array('type' => 'submit', 'label' => Text::get('form-accept-button'), 'class' => 'inline ok')));
        } else {
            $individual_rewards["individual_reward-{$individual_reward->id}"] = array('class' => 'reward individual_reward', 'view' => 'view/dashboard/translates/rewards/reward.html.php', 'data' => array('reward' => $individual_reward));
        }
    }
}
$sfid = 'sf-project-rewards';
Esempio n. 3
0
 *  Goteo is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Goteo 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with Goteo.  If not, see <http://www.gnu.org/licenses/agpl.txt>.
 *
 */
use Goteo\Core\View, Goteo\Library\Text, Goteo\Model\Project\Reward, Goteo\Model\Invest;
$icons = Reward::icons('individual');
$project = $this['project'];
$rewards = $this['rewards'];
// recompensas ordenadas por importe
uasort($rewards, function ($a, $b) {
    if ($a->amount == $b->amount) {
        return 0;
    }
    return $a->amount > $b->amount ? 1 : -1;
});
$invests = $this['invests'];
$filter = $this['filter'];
// al ir mostrando, quitamos los que no cumplan
// pending = solo los que tienen alguna recompensa pendientes
// fulfilled = solo los que tienen todas las recompensas cumplidas
// resign = solo los que hicieron renuncia a recompensa
Esempio n. 4
0
 public static function process($action = 'list', $id = null, $filters = array())
 {
     $errors = array();
     // reubicando aporte,
     if ($action == 'move') {
         // el aporte original
         $original = Model\Invest::get($id);
         $userData = Model\User::getMini($original->user);
         $projectData = Model\Project::getMini($original->project);
         //el original tiene que ser de tpv o cash y estar como 'cargo ejecutado'
         if ($original->method == 'paypal' || $original->status != 1) {
             Message::Error('No se puede reubicar este aporte!');
             throw new Redirection('/admin/accounts');
         }
         // generar aporte manual y caducar el original
         if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['move'])) {
             // si falta proyecto, error
             $projectNew = $_POST['project'];
             // @TODO a saber si le toca dinero de alguna convocatoria
             $campaign = null;
             $invest = new Model\Invest(array('amount' => $original->amount, 'user' => $original->user, 'project' => $projectNew, 'account' => $userData->email, 'method' => 'cash', 'status' => '1', 'invested' => date('Y-m-d'), 'charged' => $original->charged, 'anonymous' => $original->anonymous, 'resign' => $original->resign, 'admin' => $_SESSION['user']->id, 'campaign' => $campaign));
             //@TODO si el proyecto seleccionado
             if ($invest->save($errors)) {
                 //recompensas que le tocan (si no era resign)
                 if (!$original->resign) {
                     // sacar recompensas
                     $rewards = Model\Project\Reward::getAll($projectNew, 'individual');
                     foreach ($rewards as $rewId => $rewData) {
                         $invest->setReward($rewId);
                         //asignar
                     }
                 }
                 // cambio estado del aporte original a 'Reubicado' (no aparece en cofinanciadores)
                 // si tuviera que aparecer lo marcaríamos como caducado
                 if ($original->setStatus('5')) {
                     // Evento Feed
                     $log = new Feed();
                     $log->setTarget($projectData->id);
                     $log->populate('Aporte reubicado', '/admin/accounts', \vsprintf("%s ha aportado %s al proyecto %s en nombre de %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('money', $_POST['amount'] . ' &euro;'), Feed::item('project', $projectData->name, $projectData->id), Feed::item('user', $userData->name, $userData->id))));
                     $log->doAdmin('money');
                     unset($log);
                     Message::Info('Aporte reubicado correctamente');
                     throw new Redirection('/admin/accounts');
                 } else {
                     $errors[] = 'A fallado al cambiar el estado del aporte original (' . $original->id . ')';
                 }
             } else {
                 $errors[] = 'Ha fallado algo al reubicar el aporte';
             }
         }
         $viewData = array('folder' => 'accounts', 'file' => 'move', 'original' => $original, 'user' => $userData, 'project' => $projectData);
         return new View('view/admin/index.html.php', $viewData);
         // fin de la historia dereubicar
     }
     // cambiando estado del aporte aporte,
     if ($action == 'update') {
         // el aporte original
         $invest = Model\Invest::get($id);
         if (!$invest instanceof Model\Invest) {
             Message::Error('No tenemos registro del aporte ' . $id);
             throw new Redirection('/admin/accounts');
         }
         $status = Model\Invest::status();
         $new = isset($_POST['status']) ? $_POST['status'] : null;
         if ($invest->issue && $_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['update']) && $_POST['resolve'] == 1) {
             Model\Invest::unsetIssue($id);
             Model\Invest::setDetail($id, 'issue-solved', 'La incidencia se ha dado por resuelta por el usuario ' . $_SESSION['user']->name);
             Message::Info('La incidencia se ha dado por resuelta');
         }
         if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['update']) && isset($new) && isset($status[$new])) {
             if ($new != $invest->status) {
                 if (Model\Invest::query("UPDATE invest SET status=:status WHERE id=:id", array(':id' => $id, ':status' => $new))) {
                     Model\Invest::setDetail($id, 'status-change' . rand(0, 9999), 'El admin ' . $_SESSION['user']->name . ' ha cambiado el estado del apote a ' . $status[$new]);
                     Message::Info('Se ha actualizado el estado del aporte');
                 } else {
                     Message::Error('Ha fallado al actualizar el estado del aporte');
                 }
             } else {
                 Message::Error('No se ha cambiado el estado');
             }
             throw new Redirection('/admin/accounts/details/' . $id);
         }
         return new View('view/admin/index.html.php', array('folder' => 'accounts', 'file' => 'update', 'invest' => $invest, 'status' => $status));
         // fin de la historia actualizar estado
     }
     // resolviendo incidencias
     if ($action == 'solve') {
         // el aporte original
         $invest = Model\Invest::get($id);
         if (!$invest instanceof Model\Invest) {
             Message::Error('No tenemos registro del aporte ' . $id);
             throw new Redirection('/admin/accounts');
         }
         $projectData = Model\Project::getMini($invest->project);
         $errors = array();
         // primero cancelar
         switch ($invest->method) {
             case 'paypal':
                 $err = array();
                 if (Paypal::cancelPreapproval($invest, $err)) {
                     $errors[] = 'Preaproval paypal cancelado.';
                     $log_text = "El admin %s ha cancelado aporte y preapproval de %s de %s mediante PayPal (id: %s) al proyecto %s del dia %s";
                 } else {
                     $txt_errors = implode('; ', $err);
                     $errors[] = 'Fallo al cancelar el preapproval en paypal: ' . $txt_errors;
                     $log_text = "El admin %s ha fallado al cancelar el aporte de %s de %s mediante PayPal (id: %s) al proyecto %s del dia %s. <br />Se han dado los siguientes errores: {$txt_errors}";
                     if ($invest->cancel()) {
                         $errors[] = 'Aporte cancelado';
                     } else {
                         $errors[] = 'Fallo al cancelar el aporte';
                     }
                 }
                 break;
             case 'tpv':
                 $err = array();
                 if (Tpv::cancelPreapproval($invest, $err)) {
                     $txt_errors = implode('; ', $err);
                     $errors[] = 'Aporte cancelado correctamente. ' . $txt_errors;
                     $log_text = "El admin %s ha anulado el cargo tpv de %s de %s mediante TPV (id: %s) al proyecto %s del dia %s";
                 } else {
                     $txt_errors = implode('; ', $err);
                     $errors[] = 'Fallo en la operación. ' . $txt_errors;
                     $log_text = "El admin %s ha fallado al solicitar la cancelación del cargo tpv de %s de %s mediante TPV (id: %s) al proyecto %s del dia %s. <br />Se han dado los siguientes errores: {$txt_errors}";
                 }
                 break;
             case 'cash':
                 if ($invest->cancel()) {
                     $log_text = "El admin %s ha cancelado aporte manual de %s de %s (id: %s) al proyecto %s del dia %s";
                     $errors[] = 'Aporte cancelado';
                 } else {
                     $log_text = "El admin %s ha fallado al cancelar el aporte manual de %s de %s (id: %s) al proyecto %s del dia %s. ";
                     $errors[] = 'Fallo al cancelar el aporte';
                 }
                 break;
         }
         // Evento Feed
         $log = new Feed();
         $log->setTarget($projectData->id);
         $log->populate('Cargo cancelado manualmente (admin)', '/admin/accounts', \vsprintf($log_text, array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('user', $userData->name, $userData->id), Feed::item('money', $invest->amount . ' &euro;'), Feed::item('system', $invest->id), Feed::item('project', $projectData->name, $projectData->id), Feed::item('system', date('d/m/Y', strtotime($invest->invested))))));
         $log->doAdmin();
         unset($log);
         // luego resolver
         if ($invest->solve($errors)) {
             // Evento Feed
             $log = new Feed();
             $log->setTarget($projectData->id);
             $log->populate('Incidencia resuelta (admin)', '/admin/accounts', \vsprintf("El admin %s ha dado por resuelta la incidencia con el botón \"Nos han hecho la transferencia\" para el aporte %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('system', $id, 'accounts/details/' . $id))));
             $log->doAdmin('admin');
             unset($log);
             Message::Info('La incidencia se ha dado por resuelta, el aporte se ha pasado a manual y cobrado');
             throw new Redirection('/admin/accounts');
         } else {
             // Evento Feed
             $log = new Feed();
             $log->setTarget($projectData->id);
             $log->populate('Fallo al resolver incidencia (admin)', '/admin/accounts', \vsprintf("Al admin %s le ha fallado el botón \"Nos han hecho la transferencia\" para el aporte %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('system', $id, 'accounts/details/' . $id))));
             $log->doAdmin('admin');
             unset($log);
             Message::Error('Ha fallado al resolver la incidencia: ' . implode(',', $errors));
             throw new Redirection('/admin/accounts/details/' . $id);
         }
     }
     // aportes manuales, cargamos la lista completa de usuarios, proyectos y campañas
     if ($action == 'add') {
         // listado de proyectos en campaña
         $projects = Model\Project::active(false, true);
         // usuarios
         $users = Model\User::getAllMini();
         // campañas
         //@CALLSYS
         $calls = array();
         // generar aporte manual
         if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['add'])) {
             $userData = Model\User::getMini($_POST['user']);
             $projectData = Model\Project::getMini($_POST['project']);
             $invest = new Model\Invest(array('amount' => $_POST['amount'], 'user' => $userData->id, 'project' => $projectData->id, 'account' => $userData->email, 'method' => 'cash', 'status' => '1', 'invested' => date('Y-m-d'), 'charged' => date('Y-m-d'), 'anonymous' => $_POST['anonymous'], 'resign' => 1, 'admin' => $_SESSION['user']->id));
             //@CALLSYS
             if ($invest->save($errors)) {
                 // Evento Feed
                 $log = new Feed();
                 $log->setTarget($projectData->id);
                 $log->populate('Aporte manual (admin)', '/admin/accounts', \vsprintf("%s ha aportado %s al proyecto %s en nombre de %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('money', $_POST['amount'] . ' &euro;'), Feed::item('project', $projectData->name, $projectData->id), Feed::item('user', $userData->name, $userData->id))));
                 $log->doAdmin('money');
                 unset($log);
                 Model\Invest::setDetail($invest->id, 'admin-created', 'Este aporte ha sido creado manualmente por el admin ' . $_SESSION['user']->name);
                 Message::Info('Aporte manual creado correctamente, seleccionar recompensa y dirección de entrega.');
                 throw new Redirection('/admin/rewards/edit/' . $invest->id);
             } else {
                 $errors[] = 'Ha fallado algo al crear el aporte manual';
             }
         }
         $viewData = array('folder' => 'accounts', 'file' => 'add', 'autocomplete' => true, 'users' => $users, 'projects' => $projects, 'calls' => $calls);
         return new View('view/admin/index.html.php', $viewData);
         // fin de la historia
     }
     // Informe de la financiación de un proyecto
     if ($action == 'report') {
         // estados de aporte
         $project = Model\Project::get($id);
         if (!$project instanceof Model\Project) {
             Message::Error('Instancia de proyecto no valida');
             throw new Redirection('/admin/accounts');
         }
         $invests = Model\Invest::getAll($id);
         $project->investors = Model\Invest::investors($id, false, true);
         $users = $project->agregateInvestors();
         $investStatus = Model\Invest::status();
         // Datos para el informe de transacciones correctas
         $Data = Model\Invest::getReportData($project->id, $project->status, $project->round, $project->passed);
         return new View('view/admin/index.html.php', array('folder' => 'accounts', 'file' => 'report', 'invests' => $invests, 'project' => $project, 'status' => $status, 'users' => $users, 'investStatus' => $investStatus, 'Data' => $Data));
     }
     // cancelar aporte antes de ejecución, solo aportes no cargados
     if ($action == 'cancel') {
         $invest = Model\Invest::get($id);
         if (!$invest instanceof Model\Invest) {
             Message::Error('No tenemos objeto para el aporte ' . $id);
             throw new Redirection('/admin/accounts');
         }
         $project = Model\Project::get($invest->project);
         $userData = Model\User::get($invest->user);
         if ($project->status > 3 && $project->status < 6) {
             $errors[] = 'No debería poderse cancelar un aporte cuando el proyecto ya está financiado. Si es imprescindible, hacerlo desde el panel de paypal o tpv';
             break;
         }
         switch ($invest->method) {
             case 'paypal':
                 $err = array();
                 if (Paypal::cancelPreapproval($invest, $err)) {
                     $errors[] = 'Preaproval paypal cancelado.';
                     $log_text = "El admin %s ha cancelado aporte y preapproval de %s de %s mediante PayPal (id: %s) al proyecto %s del dia %s";
                 } else {
                     $txt_errors = implode('; ', $err);
                     $errors[] = 'Fallo al cancelar el preapproval en paypal: ' . $txt_errors;
                     $log_text = "El admin %s ha fallado al cancelar el aporte de %s de %s mediante PayPal (id: %s) al proyecto %s del dia %s. <br />Se han dado los siguientes errores: {$txt_errors}";
                     if ($invest->cancel()) {
                         $errors[] = 'Aporte cancelado';
                     } else {
                         $errors[] = 'Fallo al cancelar el aporte';
                     }
                 }
                 break;
             case 'tpv':
                 $err = array();
                 if (Tpv::cancelPreapproval($invest, $err)) {
                     $txt_errors = implode('; ', $err);
                     $errors[] = 'Aporte cancelado correctamente. ' . $txt_errors;
                     $log_text = "El admin %s ha anulado el cargo tpv de %s de %s mediante TPV (id: %s) al proyecto %s del dia %s";
                 } else {
                     $txt_errors = implode('; ', $err);
                     $errors[] = 'Fallo en la operación. ' . $txt_errors;
                     $log_text = "El admin %s ha fallado al solicitar la cancelación del cargo tpv de %s de %s mediante TPV (id: %s) al proyecto %s del dia %s. <br />Se han dado los siguientes errores: {$txt_errors}";
                 }
                 break;
             case 'cash':
                 if ($invest->cancel()) {
                     $log_text = "El admin %s ha cancelado aporte manual de %s de %s (id: %s) al proyecto %s del dia %s";
                     $errors[] = 'Aporte cancelado';
                 } else {
                     $log_text = "El admin %s ha fallado al cancelar el aporte manual de %s de %s (id: %s) al proyecto %s del dia %s. ";
                     $errors[] = 'Fallo al cancelar el aporte';
                 }
                 break;
         }
         // Evento Feed
         $log = new Feed();
         $log->setTarget($project->id);
         $log->populate('Cargo cancelado manualmente (admin)', '/admin/accounts', \vsprintf($log_text, array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('user', $userData->name, $userData->id), Feed::item('money', $invest->amount . ' &euro;'), Feed::item('system', $invest->id), Feed::item('project', $project->name, $project->id), Feed::item('system', date('d/m/Y', strtotime($invest->invested))))));
         $log->doAdmin();
         Model\Invest::setDetail($invest->id, 'manually-canceled', $log->html);
         unset($log);
     }
     // ejecutar cargo ahora!!, solo aportes no ejecutados
     // si esta pendiente, ejecutar el cargo ahora (como si fuera final de ronda), deja pendiente el pago secundario
     if ($action == 'execute' && $invest->status == 0) {
         $invest = Model\Invest::get($id);
         if (!$invest instanceof Model\Invest) {
             Message::Error('No tenemos objeto para el aporte ' . $id);
             throw new Redirection('/admin/accounts');
         }
         $project = Model\Project::get($invest->project);
         $userData = Model\User::get($invest->user);
         switch ($invest->method) {
             case 'paypal':
                 // a ver si tiene cuenta paypal
                 $projectAccount = Model\Project\Account::get($invest->project);
                 if (empty($projectAccount->paypal)) {
                     // Erroraco!
                     $errors[] = 'El proyecto no tiene cuenta paypal!!, ponersela en la seccion Contrato del dashboard del autor';
                     $log_text = null;
                     // Evento Feed
                     $log = new Feed();
                     $log->setTarget($project->id);
                     $log->populate('proyecto sin cuenta paypal (admin)', '/admin/projects', \vsprintf('El proyecto %s aun no ha puesto su %s !!!', array(Feed::item('project', $project->name, $project->id), Feed::item('relevant', 'cuenta PayPal'))));
                     $log->doAdmin('project');
                     unset($log);
                     break;
                 }
                 $invest->account = $projectAccount->paypal;
                 if (Paypal::pay($invest, $errors)) {
                     $errors[] = 'Cargo paypal correcto';
                     $log_text = "El admin %s ha ejecutado el cargo a %s por su aporte de %s mediante PayPal (id: %s) al proyecto %s del dia %s";
                     $invest->status = 1;
                     // si era incidencia la desmarcamos
                     if ($invest->issue) {
                         Model\Invest::unsetIssue($invest->id);
                         Model\Invest::setDetail($invest->id, 'issue-solved', 'La incidencia se ha dado por resuelta al ejecutar el aporte manualmente por el admin ' . $_SESSION['user']->name);
                     }
                 } else {
                     $txt_errors = implode('; ', $errors);
                     $errors[] = 'Fallo al ejecutar cargo paypal: ' . $txt_errors . '<strong>POSIBLE INCIDENCIA NO COMUNICADA Y APORTE NO CANCELADO, HAY QUE TRATARLA MANUALMENTE</strong>';
                     $log_text = "El admin %s ha fallado al ejecutar el cargo a %s por su aporte de %s mediante PayPal (id: %s) al proyecto %s del dia %s. <br />Se han dado los siguientes errores: {$txt_errors}";
                 }
                 break;
             case 'tpv':
                 if (Tpv::pay($invest, $errors)) {
                     $errors[] = 'Cargo sermepa correcto';
                     $log_text = "El admin %s ha ejecutado el cargo a %s por su aporte de %s mediante TPV (id: %s) al proyecto %s del dia %s";
                     $invest->status = 1;
                 } else {
                     $txt_errors = implode('; ', $errors);
                     $errors[] = 'Fallo al ejecutar cargo sermepa: ' . $txt_errors;
                     $log_text = "El admin %s ha fallado al ejecutar el cargo a %s por su aporte de %s mediante TPV (id: %s) al proyecto %s del dia %s <br />Se han dado los siguientes errores: {$txt_errors}";
                 }
                 break;
             case 'cash':
                 $invest->setStatus('1');
                 $errors[] = 'Aporte al contado, nada que ejecutar.';
                 $log_text = "El admin %s ha dado por ejecutado el aporte manual a nombre de %s por la cantidad de %s (id: %s) al proyecto %s del dia %s";
                 $invest->status = 1;
                 break;
         }
         if (!empty($log_text)) {
             // Evento Feed
             $log = new Feed();
             $log->setTarget($project->id);
             $log->populate('Cargo ejecutado manualmente (admin)', '/admin/accounts', \vsprintf($log_text, array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('user', $userData->name, $userData->id), Feed::item('money', $invest->amount . ' &euro;'), Feed::item('system', $invest->id), Feed::item('project', $project->name, $project->id), Feed::item('system', date('d/m/Y', strtotime($invest->invested))))));
             $log->doAdmin();
             Model\Invest::setDetail($invest->id, 'manually-executed', $log->html);
             unset($log);
         }
     }
     // visor de logs
     if ($action == 'viewer') {
         return new View('view/admin/index.html.php', array('folder' => 'accounts', 'file' => 'viewer'));
     }
     if ($action == 'resign' && !empty($id) && $_GET['token'] == md5('resign')) {
         if ($invest->setResign(true)) {
             Model\Invest::setDetail($invest->id, 'manually-resigned', 'Se ha marcado como donativo independientemente de las recompensas');
             throw new Redirection('/admin/accounts/detail/' . $invest->id);
         } else {
             $errors[] = 'Ha fallado al marcar donativo';
         }
     }
     if (!empty($errors)) {
         Message::Error(implode('<br />', $errors));
     }
     // tipos de aporte
     $methods = Model\Invest::methods();
     // estados del proyecto
     $status = Model\Project::status();
     $procStatus = Model\Project::procStatus();
     // estados de aporte
     $investStatus = Model\Invest::status();
     // listado de proyectos
     $projects = Model\Invest::projects();
     // usuarios cofinanciadores
     $users = Model\Invest::users(true);
     // campañas que tienen aportes
     $calls = Model\Invest::calls();
     // extras
     $types = array('donative' => 'Solo los donativos', 'anonymous' => 'Solo los anónimos', 'manual' => 'Solo los manuales', 'campaign' => 'Solo con riego');
     // filtros de revisión de proyecto
     $review = array('collect' => 'Recaudado', 'paypal' => 'Rev. PayPal', 'tpv' => 'Rev. TPV', 'online' => 'Pagos Online');
     $issue = array('show' => 'Solamente las incidencias', 'hide' => 'Ocultar las incidencias');
     /// detalles de una transaccion
     if ($action == 'details') {
         $invest = Model\Invest::get($id);
         $project = Model\Project::get($invest->project);
         $userData = Model\User::get($invest->user);
         return new View('view/admin/index.html.php', array('folder' => 'accounts', 'file' => 'details', 'invest' => $invest, 'project' => $project, 'user' => $userData, 'details' => $details, 'status' => $status, 'investStatus' => $investStatus));
     }
     // listado de aportes
     if ($filters['filtered'] == 'yes') {
         $list = Model\Invest::getList($filters, null, 999);
     } else {
         $list = array();
     }
     $viewData = array('folder' => 'accounts', 'file' => 'list', 'list' => $list, 'filters' => $filters, 'users' => $users, 'projects' => $projects, 'calls' => $calls, 'review' => $review, 'methods' => $methods, 'types' => $types, 'status' => $status, 'procStatus' => $procStatus, 'issue' => $issue, 'investStatus' => $investStatus);
     return new View('view/admin/index.html.php', $viewData);
 }
Esempio n. 5
0
 private function process_rewards(&$project, &$errors)
 {
     if (!isset($_POST['process_rewards'])) {
         return false;
     }
     $types = Model\Project\Reward::icons('');
     //tratar retornos sociales
     foreach ($project->social_rewards as $k => $reward) {
         if (!empty($_POST["social_reward-{$reward->id}-remove"])) {
             unset($project->social_rewards[$k]);
             continue;
         }
         if (isset($_POST['social_reward-' . $reward->id . '-reward'])) {
             $reward->reward = $_POST['social_reward-' . $reward->id . '-reward'];
             $reward->description = $_POST['social_reward-' . $reward->id . '-description'];
             $reward->icon = $_POST['social_reward-' . $reward->id . '-icon'];
             if ($reward->icon == 'other') {
                 $reward->other = $_POST['social_reward-' . $reward->id . '-other'];
             }
             $reward->license = $_POST['social_reward-' . $reward->id . '-' . $reward->icon . '-license'];
             $reward->icon_name = $types[$reward->icon]->name;
         }
     }
     // retornos individuales
     foreach ($project->individual_rewards as $k => $reward) {
         if (!empty($_POST["individual_reward-{$reward->id}-remove"])) {
             unset($project->individual_rewards[$k]);
             continue;
         }
         if (isset($_POST['individual_reward-' . $reward->id . '-reward'])) {
             $reward->reward = $_POST['individual_reward-' . $reward->id . '-reward'];
             $reward->description = $_POST['individual_reward-' . $reward->id . '-description'];
             $reward->icon = $_POST['individual_reward-' . $reward->id . '-icon'];
             if ($reward->icon == 'other') {
                 $reward->other = $_POST['individual_reward-' . $reward->id . '-other'];
             }
             $reward->amount = $_POST['individual_reward-' . $reward->id . '-amount'];
             $reward->units = $_POST['individual_reward-' . $reward->id . '-units'];
             $reward->icon_name = $types[$reward->icon]->name;
         }
     }
     // tratar nuevos retornos
     if (!empty($_POST['social_reward-add'])) {
         $project->social_rewards[] = new Model\Project\Reward(array('type' => 'social', 'project' => $project->id, 'reward' => 'Nuevo retorno colectivo', 'icon' => '', 'license' => ''));
     }
     if (!empty($_POST['individual_reward-add'])) {
         $project->individual_rewards[] = new Model\Project\Reward(array('type' => 'individual', 'project' => $project->id, 'reward' => 'Nueva recompensa individual', 'icon' => '', 'amount' => '', 'units' => ''));
     }
     return true;
 }
Esempio n. 6
0
 public static function Projects($debug = false)
 {
     // proyectos a notificar
     $projects = Model\Project::review();
     // para cada uno,
     foreach ($projects as $project) {
         // por ahora solo tratamos los de primera ronda y hasta 2 meses tras la financiación
         if ($project->days > 40 || $project->days > 360) {
             continue;
         }
         if ($debug) {
             echo "Proyecto {$project->name}, Impulsor:  {$project->user->name}, email: {$project->user->email}, estado {$project->status}, lleva {$project->days} dias<br />";
         }
         // primero los que no se bloquean
         // Recuerdo al autor proyecto, 2 meses despues de campaña finalizada
         if ($project->days == 140) {
             // si quedan recompensas/retornos pendientes por cumplir
             if (!Model\Project\Reward::areFulfilled($project->id) || !Model\Project\Reward::areFulfilled($project->id, 'social')) {
                 if ($debug) {
                     echo "Recompensas/Retornos pendientes<br />";
                 }
                 Send::toOwner('2m_after', $project);
             } else {
                 if ($debug) {
                     echo "Recompensas/Retornos cumplidas, no se envía<br />";
                 }
             }
         }
         // Recuerdo al autor proyecto, 8 meses despues de campaña finalizada
         if ($project->days == 320) {
             // si quedan retornos pendientes por cumplir
             if (!Model\Project\Reward::areFulfilled($project->id, 'social')) {
                 if ($debug) {
                     echo "Retornos pendientes<br />";
                 }
                 Send::toOwner('8m_after', $project);
             } else {
                 if ($debug) {
                     echo "Retornos cumplidos, no se envía<br />";
                 }
             }
         }
         // ahora checkeamos bloqueo de consejos
         $prefs = Model\User::getPreferences($project->owner);
         if ($prefs->tips) {
             if ($debug) {
                 echo "Bloqueado por preferencias<hr />";
             }
             continue;
         }
         // flag de aviso
         $avisado = false;
         // Consejos/avisos puntuales
         switch ($project->days) {
             // NO condicionales
             case 1:
                 // Difunde, difunde, difunde
             // Difunde, difunde, difunde
             case 2:
                 // Comienza por lo más próximo
             // Comienza por lo más próximo
             case 3:
                 // Una acción a diario, por pequeña que sea
             // Una acción a diario, por pequeña que sea
             case 4:
                 // Llama a todas las puertas
             // Llama a todas las puertas
             case 5:
                 // Busca dónde está tu comunidad
             // Busca dónde está tu comunidad
             case 8:
                 // Agradece en público e individualmente
                 $template = 'tip_' . $project->days;
                 if ($debug) {
                     echo "Envío {$template}<br />";
                 }
                 Send::toOwner($template, $project);
                 break;
                 // periodico condicional
             // periodico condicional
             case 6:
                 // Publica novedades!
                 // y  se repite cada 6 días (fechas libres) mientras no haya posts
             // Publica novedades!
             // y  se repite cada 6 días (fechas libres) mientras no haya posts
             case 12:
             case 18:
             case 24:
             case 30:
             case 36:
                 // si ya hay novedades, nada
                 if (Model\Blog::hasUpdates($project->id)) {
                     if ($debug) {
                         echo "Ya ha publicado novedades<br />";
                     }
                 } else {
                     if ($debug) {
                         echo "Envío aviso de que no ha publicado novedades<br />";
                     }
                     Send::toOwner('any_update', $project);
                     $avisado = true;
                 }
                 break;
                 // comprobación periódica pero solo un envío
             // comprobación periódica pero solo un envío
             case 7:
                 // Apóyate en quienes te van apoyando ,  si más de 20 cofinanciadores
                 // o en cuanto llegue a 20 backers (en fechas libres)
             // Apóyate en quienes te van apoyando ,  si más de 20 cofinanciadores
             // o en cuanto llegue a 20 backers (en fechas libres)
             case 14:
             case 17:
             case 21:
             case 24:
             case 27:
                 // Si ya se mandó esta plantilla (al llegar a los 20 por primera vez) no se envía de nuevo
                 $sql = "\n                            SELECT\n                                id\n                            FROM mail\n                            WHERE mail.email = :email\n                            AND mail.template = 46\n                            ORDER BY mail.date DESC\n                            LIMIT 1";
                 $query = Model\Project::query($sql, array(':email' => $project->user->email));
                 $sended = $query->fetchColumn(0);
                 if (!$sended) {
                     if ($project->num_investors >= 20) {
                         if ($debug) {
                             echo "Tiene 20 backers y no se le habia enviado aviso antes<br />";
                         }
                         Send::toOwner('20_backers', $project);
                     } else {
                         if ($debug) {
                             echo "No llega a los 20 backers<br />";
                         }
                     }
                 } else {
                     if ($debug) {
                         echo "Ya enviado<br />";
                     }
                 }
                 break;
             case 9:
                 // Busca prescriptores e implícalos
                 // si no tiene padrinos
                 if ($project->patrons > 0) {
                     if ($debug) {
                         echo "Tiene padrino<br />";
                     }
                 } else {
                     if ($debug) {
                         echo "No tiene padrino<br />";
                     }
                     Send::toOwner('tip_9', $project);
                 }
                 break;
             case 10:
                 // Luce tus recompensas y retornos
                 // que no se envie a los que solo tienen recompensas de agradecimiento
                 $thanksonly = true;
                 // recompensas
                 $rewards = Model\Project\Reward::getAll($project->id, 'individual', \LANG);
                 foreach ($rewards as $rew) {
                     if ($rew->icon != 'thanks') {
                         $thanksonly = false;
                         break;
                         // ya salimos del bucle, no necesitamos más
                     }
                 }
                 if ($thanksonly) {
                     if ($debug) {
                         echo "Solo tiene recompensas de agradecimiento<br />";
                     }
                 } else {
                     if ($debug) {
                         echo "Tienen recompensas<br />";
                     }
                     uasort($rewards, function ($a, $b) {
                         if ($a->amount == $b->amount) {
                             return 0;
                         }
                         return $a->amount > $b->amount ? 1 : -1;
                     });
                     // sacar la primera y la última
                     $lower = reset($rewards);
                     $project->lower = $lower->reward;
                     $higher = end($rewards);
                     $project->higher = $higher->reward;
                     Send::toOwner('tip_10', $project);
                 }
                 break;
             case 11:
                 // Refresca tu mensaje de motivacion
                 // si no tiene video motivacional
                 if (empty($project->video)) {
                     if ($debug) {
                         echo "No tiene video motivacional<br />";
                     }
                     Send::toOwner('tip_11', $project);
                 } else {
                     if ($debug) {
                         echo "Tiene video motivacional<br />";
                     }
                 }
                 break;
             case 15:
                 // Sigue los avances y calcula lo que falta
                 // si no ha llegado al mínimo
                 if ($project->invested < $project->mincost) {
                     if ($debug) {
                         echo "No ha llegado al mínimo<br />";
                     }
                     Send::toOwner('tip_15', $project);
                 } else {
                     if ($debug) {
                         echo "Ha llegado al mínimo<br />";
                     }
                 }
                 break;
             case 25:
                 // No bajes la guardia!
                 // si no ha llegado al mínimo
                 if ($project->invested < $project->mincost) {
                     if ($debug) {
                         echo "No ha llegado al mínimo<br />";
                     }
                     Send::toOwner('two_weeks', $project);
                 } else {
                     if ($debug) {
                         echo "Ha llegado al mínimo<br />";
                     }
                 }
                 break;
             case 32:
                 // Al proyecto le faltan 8 días para archivarse
                 // si no ha llegado al mínimo
                 if ($project->invested < $project->mincost) {
                     if ($debug) {
                         echo "No ha llegado al mínimo<br />";
                     }
                     Send::toOwner('8_days', $project);
                 } else {
                     if ($debug) {
                         echo "Ha llegado al mínimo<br />";
                     }
                 }
                 break;
             case 38:
                 // Al proyecto le faltan 2 días para archivarse
                 // si no ha llegado al mínimo pero está por encima del 70%
                 if ($project->invested < $project->mincost && $project->percent >= 70) {
                     if ($debug) {
                         echo "No ha llegado al mínimo<br />";
                     }
                     Send::toOwner('2_days', $project);
                 } else {
                     if ($debug) {
                         echo "Ha llegado al mínimo o lleva menos de 70%<br />";
                     }
                 }
                 break;
         }
         // Avisos periodicos
         // si lleva más de 15 días: si no se han publicado novedades en la última semana
         // Ojo! que si no a enviado ninguna no lanza este sino la de cada 6 días
         if (!$avisado && $project->days > 15) {
             if ($debug) {
                 echo "ya lleva una quincena de campaña, verificamos novedades<br />";
             }
             // veamos si ya le avisamos hace una semana
             // Si ya se mandó esta plantilla (al llegar a los 20 por primera vez) no se envía de nuevo
             $sql = "\n                        SELECT\n                            id,\n                            DATE_FORMAT(\n                                from_unixtime(unix_timestamp(now()) - unix_timestamp(date))\n                                , '%j'\n                            ) as days\n                        FROM mail\n                        WHERE mail.email = :email\n                        AND mail.template = 23\n                        ORDER BY mail.date DESC\n                        LIMIT 1";
             $query = Model\Project::query($sql, array(':email' => $project->user->email));
             $lastsend = $query->fetchObject();
             if (!$lastsend->id || $lastsend->days > 7) {
                 // veamos cuanto hace de la última novedad
                 $sql = "\n                            SELECT\n                                DATE_FORMAT(\n                                    from_unixtime(unix_timestamp(now()) - unix_timestamp(date))\n                                    , '%j'\n                                ) as days\n                            FROM post\n                            INNER JOIN blog\n                                ON  post.blog = blog.id\n                                AND blog.type = 'project'\n                                AND blog.owner = :project\n                            WHERE post.publish = 1\n                            ORDER BY post.date DESC\n                            LIMIT 1";
                 $query = Model\Project::query($sql, array(':project' => $project->id));
                 $lastUpdate = $query->fetchColumn(0);
                 if ($lastUpdate > 7) {
                     if ($debug) {
                         echo "Ultima novedad es de hace más de una semana<br />";
                     }
                     Send::toOwner('no_updates', $project);
                 } elseif (is_numeric($lastUpdate)) {
                     if ($debug) {
                         echo "Publicó novedad hace menos de una semana<br />";
                     }
                 } else {
                     if ($debug) {
                         echo "No se ha publicado nada, recibirá el de cada 6 días<br />";
                     }
                 }
             } else {
                 if ($debug) {
                     echo "Se le avisó por novedades hace menos de una semana<br />";
                 }
             }
         }
         if ($debug) {
             echo "<hr />";
         }
     }
     if ($debug) {
         echo "<br />Auto-tips Listo!<hr />";
     }
     return;
 }
Esempio n. 7
0
 public function projects($option = 'summary', $action = 'list', $id = null)
 {
     $user = $_SESSION['user'];
     $errors = array();
     // verificación de proyectos y proyecto de trabajo
     list($project, $projects) = Dashboard\Projects::verifyProject($user, $action);
     // teniendo proyecto de trabajo, comprobar si el proyecto esta en estado de tener blog
     if ($option == 'updates') {
         $blog = Dashboard\Projects::verifyBlog($project);
     }
     // sacaexcel de cofinanciadores
     if ($option == 'rewards' && $action == 'table') {
         $response = new \Goteo\Controller\Sacaexcel();
         return $response->index('investors', $project->id);
     }
     // ojo si no tiene retornos
     if ($option == 'commons' && empty($project->social_rewards)) {
         Message::Error('Este proyecto no tiene retornos colectivos');
         throw new Redirection('/dashboard/projects/');
     }
     // procesamiento de formularios
     if ($_SERVER['REQUEST_METHOD'] == 'POST') {
         switch ($option) {
             // gestionar retornos (o mensaje a los mensajeros)
             case 'messegers':
             case 'rewards':
                 // sacamos del post el filtro y el orden
                 if ($action == 'filter') {
                     $_SESSION['dashboard-rewards-filter'] = isset($_POST['filter']) ? $_POST['filter'] : $_SESSION['dashboard-rewards-filter'];
                     $_SESSION['dashboard-rewards-order'] = isset($_POST['order']) ? $_POST['order'] : $_SESSION['dashboard-rewards-order'];
                 }
                 //procesamos el envio de mails
                 if ($action == 'message') {
                     Dashboard\Projects::process_mailing($option, $project);
                     // y lo devolvemos a donde estaba
                     throw new Redirection('/dashboard/projects/' . $option);
                 }
                 break;
                 // colaboraciones
             // colaboraciones
             case 'supports':
                 if ($action == 'save') {
                     $project = Dashboard\Projects::process_supports($project, $errors);
                 }
                 break;
             case 'updates':
                 // verificación: si no llega blog correcto no lo procesamos
                 if (empty($_POST['blog']) || $_POST['blog'] != $blog->id) {
                     throw new Redirection('/dashboard/projects/summary');
                 }
                 list($action, $id) = Dashboard\Projects::process_updates($action, $project, $errors);
                 break;
         }
     }
     // SubControlador para add, edit, delete y list
     // devuelve $post en las acciones add y edit y $posts en delete y list
     // maneja por referencia $action, $posts y $errors
     if ($option == 'updates') {
         list($post, $posts) = Dashboard\Projects::prepare_updates($action, $id, $blog->id);
     }
     // view data basico para esta seccion
     $viewData = array('menu' => self::menu(), 'section' => __FUNCTION__, 'option' => $option, 'action' => $action, 'projects' => $projects, 'errors' => $errors);
     switch ($option) {
         case 'summary':
             // los datos json de invests y visitors_data
             $viewData['data'] = Dashboard\Projects::graph($project->id);
             break;
             // gestionar recompensas
         // gestionar recompensas
         case 'rewards':
             // recompensas ofrecidas
             $viewData['rewards'] = Model\Project\Reward::getAll($project->id, 'individual', LANG);
             // aportes para este proyecto
             $viewData['invests'] = Model\Invest::getAll($project->id);
             // ver por (esto son orden y filtros)
             $viewData['filter'] = $_SESSION['dashboard-rewards-filter'];
             $viewData['order'] = $_SESSION['dashboard-rewards-order'];
             break;
             // gestionar retornos
         // gestionar retornos
         case 'commons':
             $icons = Model\Icon::getAll('social');
             foreach ($icons as $key => $icon) {
                 $icons[$key] = $icon->name;
             }
             $viewData['icons'] = $icons;
             break;
             // listar mensajeadores
         // listar mensajeadores
         case 'messegers':
             $viewData['messegers'] = Model\Message::getMessegers($project->id);
             break;
             // editar colaboraciones
         // editar colaboraciones
         case 'supports':
             $viewData['types'] = Model\Project\Support::types();
             // para mantener registros desplegados
             if ($_POST) {
                 foreach ($_POST as $k => $v) {
                     if (!empty($v) && preg_match('/support-(\\d+)-edit/', $k, $r)) {
                         $viewData[$k] = true;
                         break;
                     }
                 }
             }
             if (!empty($_POST['support-add'])) {
                 $last = end($project->supports);
                 if ($last !== false) {
                     $viewData['support-' . $last->id . '-edit'] = true;
                 }
             }
             $project->supports = Model\Project\Support::getAll($project->id);
             break;
             // publicar actualizaciones
         // publicar actualizaciones
         case 'updates':
             $viewData['blog'] = $blog;
             $viewData['posts'] = $posts;
             $viewData['post'] = $post;
             break;
     }
     $viewData['project'] = $project;
     return new View('view/dashboard/index.html.php', $viewData);
 }
Esempio n. 8
0
 /**
  * actualiza en la tabla los datos del proyecto
  * @param array $project->errors para guardar los errores de datos del formulario, los errores de proceso se guardan en $project->errors['process']
  */
 public function save(&$errors = array())
 {
     if ($this->dontsave) {
         return false;
     }
     if (!$this->validate($errors)) {
         return false;
     }
     try {
         // fail para pasar por todo antes de devolver false
         $fail = false;
         // los nif sin guiones, espacios ni puntos
         $this->contract_nif = str_replace(array('_', '.', ' ', '-', ',', ')', '('), '', $this->contract_nif);
         $this->entity_cif = str_replace(array('_', '.', ' ', '-', ',', ')', '('), '', $this->entity_cif);
         // Image
         if (is_array($this->image) && !empty($this->image['name'])) {
             $image = new Image($this->image);
             if ($image->save($errors)) {
                 $this->gallery[] = $image;
                 $this->image = $image->id;
                 /**
                  * Guarda la relación NM en la tabla 'project_image'.
                  */
                 if (!empty($image->id)) {
                     self::query("REPLACE project_image (project, image) VALUES (:project, :image)", array(':project' => $this->id, ':image' => $image->id));
                 }
             }
         }
         $fields = array('contract_name', 'contract_nif', 'contract_email', 'contract_entity', 'contract_birthdate', 'entity_office', 'entity_name', 'entity_cif', 'phone', 'address', 'zipcode', 'location', 'country', 'secondary_address', 'post_address', 'post_zipcode', 'post_location', 'post_country', 'name', 'subtitle', 'image', 'description', 'motivation', 'video', 'video_usubs', 'about', 'goal', 'related', 'reward', 'keywords', 'media', 'media_usubs', 'currently', 'project_location', 'scope', 'resource', 'comment', 'evaluation');
         $set = '';
         $values = array();
         foreach ($fields as $field) {
             if ($set != '') {
                 $set .= ', ';
             }
             $set .= "{$field} = :{$field}";
             $values[":{$field}"] = $this->{$field};
         }
         // Solamente marcamos updated cuando se envia a revision desde el superform o el admin
         //				$set .= ", updated = :updated";
         //				$values[':updated'] = date('Y-m-d');
         $values[':id'] = $this->id;
         $sql = "UPDATE project SET " . $set . " WHERE id = :id";
         if (!self::query($sql, $values)) {
             $errors[] = $sql . '<pre>' . print_r($values, 1) . '</pre>';
             $fail = true;
         }
         //                echo "$sql<br />";
         // y aquí todas las tablas relacionadas
         // cada una con sus save, sus new y sus remove
         // quitar las que tiene y no vienen
         // añadir las que vienen y no tiene
         //categorias
         $tiene = Project\Category::get($this->id);
         $viene = $this->categories;
         $quita = array_diff_assoc($tiene, $viene);
         $guarda = array_diff_assoc($viene, $tiene);
         foreach ($quita as $key => $item) {
             $category = new Project\Category(array('id' => $item, 'project' => $this->id));
             if (!$category->remove($errors)) {
                 $fail = true;
             }
         }
         foreach ($guarda as $key => $item) {
             if (!$item->save($errors)) {
                 $fail = true;
             }
         }
         // recuperamos las que le quedan si ha cambiado alguna
         if (!empty($quita) || !empty($guarda)) {
             $this->categories = Project\Category::get($this->id);
         }
         //skills
         $tiene = Project\Skill::get($this->id);
         $viene = $this->skills;
         $quita = array_diff_assoc($tiene, $viene);
         $guarda = array_diff_assoc($viene, $tiene);
         foreach ($quita as $key => $item) {
             $skill = new Project\Skill(array('id' => $item, 'project' => $this->id));
             if (!$skill->remove($errors)) {
                 $fail = true;
             }
         }
         foreach ($guarda as $key => $item) {
             if (!$item->save($errors)) {
                 $fail = true;
             }
         }
         // recuperamos las que le quedan si ha cambiado alguna
         if (!empty($quita) || !empty($guarda)) {
             $this->skills = Project\Skill::get($this->id);
         }
         //costes
         $tiene = Project\Cost::getAll($this->id);
         $viene = $this->costs;
         $quita = array_diff_key($tiene, $viene);
         $guarda = array_diff_key($viene, $tiene);
         foreach ($quita as $key => $item) {
             if (!$item->remove($errors)) {
                 $fail = true;
             } else {
                 unset($tiene[$key]);
             }
         }
         foreach ($guarda as $key => $item) {
             if (!$item->save($errors)) {
                 $fail = true;
             }
         }
         /* Ahora, los que tiene y vienen. Si el contenido es diferente, hay que guardarlo*/
         foreach ($tiene as $key => $row) {
             // a ver la diferencia con el que viene
             if ($row != $viene[$key]) {
                 if (!$viene[$key]->save($errors)) {
                     $fail = true;
                 }
             }
         }
         if (!empty($quita) || !empty($guarda)) {
             $this->costs = Project\Cost::getAll($this->id);
         }
         // recalculo de minmax
         $this->minmax();
         //retornos colectivos
         $tiene = Project\Reward::getAll($this->id, 'social');
         $viene = $this->social_rewards;
         $quita = array_diff_key($tiene, $viene);
         $guarda = array_diff_key($viene, $tiene);
         foreach ($quita as $key => $item) {
             if (!$item->remove($errors)) {
                 $fail = true;
             } else {
                 unset($tiene[$key]);
             }
         }
         foreach ($guarda as $key => $item) {
             if (!$item->save($errors)) {
                 $fail = true;
             }
         }
         /* Ahora, los que tiene y vienen. Si el contenido es diferente, hay que guardarlo*/
         foreach ($tiene as $key => $row) {
             // a ver la diferencia con el que viene
             if ($row != $viene[$key]) {
                 if (!$viene[$key]->save($errors)) {
                     $fail = true;
                 }
             }
         }
         if (!empty($quita) || !empty($guarda)) {
             $this->social_rewards = Project\Reward::getAll($this->id, 'social');
         }
         //recompenssas individuales
         $tiene = Project\Reward::getAll($this->id, 'individual');
         $viene = $this->individual_rewards;
         $quita = array_diff_key($tiene, $viene);
         $guarda = array_diff_key($viene, $tiene);
         foreach ($quita as $key => $item) {
             if (!$item->remove($errors)) {
                 $fail = true;
             } else {
                 unset($tiene[$key]);
             }
         }
         foreach ($guarda as $key => $item) {
             if (!$item->save($errors)) {
                 $fail = true;
             }
         }
         /* Ahora, los que tiene y vienen. Si el contenido es diferente, hay que guardarlo*/
         foreach ($tiene as $key => $row) {
             // a ver la diferencia con el que viene
             if ($row != $viene[$key]) {
                 if (!$viene[$key]->save($errors)) {
                     $fail = true;
                 }
             }
         }
         if (!empty($quita) || !empty($guarda)) {
             $this->individual_rewards = Project\Reward::getAll($this->id, 'individual');
         }
         // colaboraciones
         $tiene = Project\Support::getAll($this->id);
         $viene = $this->supports;
         $quita = array_diff_key($tiene, $viene);
         // quitar los que tiene y no viene
         $guarda = array_diff_key($viene, $tiene);
         // añadir los que viene y no tiene
         foreach ($quita as $key => $item) {
             if (!$item->remove($errors)) {
                 $fail = true;
             } else {
                 unset($tiene[$key]);
             }
         }
         foreach ($guarda as $key => $item) {
             if (!$item->save($errors)) {
                 $fail = true;
             }
         }
         /* Ahora, los que tiene y vienen. Si el contenido es diferente, hay que guardarlo*/
         foreach ($tiene as $key => $row) {
             // a ver la diferencia con el que viene
             if ($row != $viene[$key]) {
                 if (!$viene[$key]->save($errors)) {
                     $fail = true;
                 }
             }
         }
         if (!empty($quita) || !empty($guarda)) {
             $this->supports = Project\Support::getAll($this->id);
         }
         //listo
         return !$fail;
     } catch (\PDOException $e) {
         $errors[] = Text::_('No se ha grabado correctamente. ') . $e->getMessage();
         //Text::get('save-project-fail');
         return false;
     }
 }