diff --git a/ChangeLog.md b/ChangeLog.md
index 0a99cea6a6322..46cbd73bb2044 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -3,7 +3,9 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
-## Version 0.1 [2020-12-25]
+- NEW : Split dialog for kanban card of type User story or Scrum task *28/07/2022* - 1.1.0
+
+## Version 1.0 [2020-12-25]
- FIX : Suppression des champs qté réalisée et quantité prévue à la création d'un sprint *21/07/2022* - 1.0.9
- FIX : Update visuel de la liste US planifiée *21/07/2022* - 1.0.8
diff --git a/admin/setup.php b/admin/setup.php
index 87ddb45b809f4..2aa7688cfe4a8 100644
--- a/admin/setup.php
+++ b/admin/setup.php
@@ -95,7 +95,8 @@
$formSetup = new FormSetup($db);
-
+/*
+ * DEMO
// Hôte
$item = $formSetup->newItem('NO_PARAM_JUST_TEXT');
$item->fieldOverride = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'];
@@ -127,6 +128,11 @@
$formSetup->newItem('Title')->setAsTitle();
+
+
+
+
+
// Setup conf MYMODULE_MYPARAM8
$item = $formSetup->newItem('MYMODULE_MYPARAM8');
$TField = array(
@@ -157,6 +163,24 @@
//$item->fieldOverride = false; // set this var to override field output will override $fieldInputOverride and $fieldOutputOverride too
//$item->fieldInputOverride = false; // set this var to override field input
//$item->fieldOutputOverride = false; // set this var to override field output
+*/
+
+
+$item = $formSetup->newItem('SP_MAX_SCRUM_TASK_STEP_QTY');
+$item->fieldAttr = array(
+ 'type' => 'number',
+ 'step' => '0.01',
+ 'min' => 0
+);
+
+$item = $formSetup->newItem('SP_MAX_SCRUM_TASK_MAX_QTY');
+$item->fieldAttr = array(
+ 'type' => 'number',
+ 'step' => getDolGlobalString('SP_MAX_SCRUM_TASK_STEP_QTY'),
+ 'min' => 0
+);
+
+$formSetup->htmlAfterOutputForm.='';
$setupnotempty =+ count($formSetup->items);
diff --git a/class/scrumcard.class.php b/class/scrumcard.class.php
index fa4d517d3ec61..cb5952843b6d9 100644
--- a/class/scrumcard.class.php
+++ b/class/scrumcard.class.php
@@ -948,6 +948,7 @@ public function getNextNumRef()
public function getScrumKanBanItemObjectFormatted(){
global $user;
+ // TODO : voir si $object peut être factorisé avec getScrumKanBanItemObjectStd mais attention il doit être compatible avec l'objet js des items de kanban
$object = new stdClass();
$object->id = 'scrumcard-' . $this->id; // kanban dom id
@@ -1098,6 +1099,56 @@ public function getScrumKanBanItemObjectFormatted(){
}
+ /**
+ * get this object formatted for ajax ans json
+ * @return stdClass
+ */
+ public function getScrumKanBanItemObjectStd(){
+
+
+ $object = new stdClass();
+ $object->objectId = $this->id;
+ $object->type = 'scrum-card';// le type dans le kanban tel que getScrumKanBanItemObjectFormatted le fait
+ $object->id = 'scrumcard-' . $this->id; // kanban dom id
+ $object->label = $this->label;
+ $object->element = $this->element;
+ $object->cardUrl = dol_buildpath('/scrumproject/scrumcard_card.php',1).'?id='.$this->id;
+ $object->title = '';
+ $object->status = intval($this->status);
+ $object->statusLabel = $this->LibStatut(intval($this->status), 1);
+ $object->contactUsersAffected = $this->liste_contact(-1,'internal',1);
+
+ /**
+ * Traitement de l'élément attaché
+ */
+
+ $object->targetelementid = $this->fk_element;
+ $object->targetelement = $this->element_type;
+
+ $res = $this->fetchElementObject();
+ if($res){
+ $object->elementObject = false;
+ if(is_callable(array($this->elementObject, 'getScrumKanBanItemObjectStd'))){
+ $object->elementObject = $this->elementObject->getScrumKanBanItemObjectStd($this, $object);
+ }
+
+ // Si gestion de l'object sans getScrumKanBanItemObjectStd : **typiquement les objects Dolibarr**
+ if(!$object->elementObject){
+ $object->elementObject = new stdClass();
+ $object->elementObject->contactUsersAffected = $this->elementObject->liste_contact(-1,'internal', 1);
+
+ if($this->elementObject->element == 'project_task'){
+ $object->type = 'project-task';
+ }else{
+ $object->type = 'scrum-card-linked';
+ }
+ }
+ }
+
+ return $object;
+ }
+
+
/**
* Return HTML string to put an input field into a page
@@ -1392,4 +1443,20 @@ public static function getInternalContactIdFromCode($code, $object, &$error = ''
}
}
+ /**
+ * Permet de spliter la carte en 2
+ * @param double $qty la quantité de la nouvelle carte
+ * @param string $newCardLabel le libelle de la nouvelle carte
+ * @return void
+ */
+ public function splitCard($qty, $newCardLabel, User $user){
+ $this->fetchElementObject();
+ if(is_callable(array($this->elementObject, 'splitCard'))){
+ return $this->elementObject->splitCard( $qty, $newCardLabel, $this, $user);
+ }else{
+ $this->error = 'splitCard not supported';
+ return false;
+ }
+ }
+
}
diff --git a/class/scrumtask.class.php b/class/scrumtask.class.php
index bd678a659de2d..23ceec858024a 100644
--- a/class/scrumtask.class.php
+++ b/class/scrumtask.class.php
@@ -1250,6 +1250,40 @@ public function getProjectTaskTimeLinkId($fk_project_task_time){
return false;
}
+
+ /**
+ * get this object formatted for ajax ans json
+ * @return stdClass
+ */
+ public function getScrumKanBanItemObjectStd(){
+
+
+ $object = new stdClass();
+ $object->objectId = $this->id;
+ $object->ref= $this->ref;
+ $object->type = 'scrum-user-story-task';// le type dans le kanban tel que getScrumKanBanItemObjectFormatted le fait
+ $object->label = $this->label;
+ $object->element = $this->element;
+ $object->cardUrl = dol_buildpath('/scrumproject/scrumtask_card.php',1).'?id='.$this->id;
+ $object->status = intval($this->status);
+ $object->statusLabel = $this->LibStatut(intval($this->status), 1);
+ $object->contactUsersAffected = $this->liste_contact(-1,'internal',1);
+
+ $object->fk_scrum_user_story_sprint = $this->fk_scrum_user_story_sprint;
+ $object->fk_scrum_user_story_sprint = $this->fk_scrum_user_story_sprint;
+ $object->qty_planned = doubleval($this->qty_planned);
+ $object->qty_consumed = doubleval($this->qty_consumed);
+
+ $object->qty_remain_for_split = 0;
+ if($this->qty_planned - $this->qty_consumed > 0){
+ $object->qty_remain_for_split = $this->qty_planned - $this->qty_consumed;
+ }
+
+ return $object;
+ }
+
+
+
/**
* @param $msg
* @return void
@@ -1270,4 +1304,86 @@ public function setErrorMsg($msg){
$this->errors[] = $msg;
}
}
+
+
+ /**
+ * Permet de spliter la carte en 2
+ * @param double $qty la quantité de la nouvelle carte
+ * @param string $newCardLabel le libelle de la nouvelle carte
+ * @param ScrumCard $scrumCard
+ * @return bool
+ */
+ public function splitCard($qty, $newCardLabel, ScrumCard $scrumCard, User $user ){
+
+ if(!class_exists('ScrumTask')){
+ require_once __DIR__ . '/scrumtask.class.php';
+ }
+ if(!class_exists('ScrumCard')){
+ require_once __DIR__ . '/scrumcard.class.php';
+ }
+
+ $qty = doubleval($qty);
+
+ $this->calcTimeSpent();
+
+ // Vérification de la liaison entre ScrumCard et ScrumTask
+ if($scrumCard->element_type != $this->element || $scrumCard->fk_element != $this->id ){
+ $this->error = 'Error : scrum card not linked';
+ $this->errors[] = $this->error;
+ return false;
+ }
+
+
+ // Vérification du temps restant
+ if($qty > $this->qty_planned - $this->qty_consumed ){
+ $this->error = 'Too much quantity';
+ $this->errors[] = $this->error;
+ return false;
+ }
+
+ // Ajout de la nouvelle ScrumTask
+ $newScrumTask = new ScrumTask($this->db);
+ $newScrumTask->fk_scrum_user_story_sprint = $this->fk_scrum_user_story_sprint;
+ $newScrumTask->description = $this->description;
+
+ $newScrumTask->qty_planned = $qty;
+ $newScrumTask->label = $newCardLabel;
+ if(empty($newCardLabel) || is_array($newCardLabel)){ $newScrumTask->label = $this->label;}
+
+ $resCreate = $newScrumTask->create($user);
+ if($resCreate<0){
+ $this->error = $newScrumTask->error;
+ $this->errors = array_merge($this->errors, $newScrumTask->errors);
+ return false;
+ }
+
+ // MISE A JOUR DE LA SCRUM TASK QUE L'ON SPLIT
+ $this->qty_planned-= $qty;
+ $resUpdate = $this->update($user);
+ if($resUpdate<1){
+ $this->error = 'Error updating ScrumTask : '.$this->error;
+ $this->errors = array_merge($this->errors, $this->errors);
+ return false;
+ }
+
+// Bloc deja effectué par $newScrumTask->create
+// // AJOUT DE LA CARD LIÉE
+// $newScrumCard = new ScrumCard($this->db);
+// if(empty($newCardLabel)){
+// $newScrumCard->label = $this->label;
+// }
+// $newScrumCard->label = $newScrumTask->label;
+// $newScrumCard->fk_element = $newScrumTask->id;
+// $newScrumCard->element_type = $newScrumTask->element;
+// $newScrumCard->fk_scrum_kanbanlist = $scrumCard->fk_scrum_kanbanlist;
+// $newScrumCard->fk_rank = $scrumCard->fk_rank;
+// $res = $newScrumCard->create($user);
+// if($res<=0){
+// $this->error = 'Error creating ScrumCard : '.$newScrumCard->error;
+// $this->errors = array_merge($this->errors, $newScrumCard->errors);
+// return false;
+// }
+
+ return true;
+ }
}
diff --git a/class/scrumuserstorysprint.class.php b/class/scrumuserstorysprint.class.php
index 7621f1cb11ff3..e5b0e9472d13e 100644
--- a/class/scrumuserstorysprint.class.php
+++ b/class/scrumuserstorysprint.class.php
@@ -146,6 +146,11 @@ class ScrumUserStorySprint extends CommonObject
public $model_pdf;
// END MODULEBUILDER PROPERTIES
+ /**
+ * valeur dynamique non stocké en base , recupérée par $this->calcTimeTaskPlanned()
+ * @var $qty_task_planned
+ */
+ public $qty_task_planned;
// If this object has a subtable with lines
@@ -945,6 +950,121 @@ public function info($id)
}
}
+
+
+ /**
+ * get this object formatted for ajax ans json
+ * @return stdClass
+ */
+ public function getScrumKanBanItemObjectStd(){
+
+ $object = new stdClass();
+ $object->objectId = $this->id;
+ $object->ref= $this->ref;
+ $object->type = 'scrum-user-story';// le type dans le kanban tel que getScrumKanBanItemObjectFormatted le fait
+ $object->label = $this->label;
+ $object->element = $this->element;
+ $object->cardUrl = dol_buildpath('/scrumproject/scrumuserstorysprint_card.php',1).'?id='.$this->id;
+
+ $object->status = intval($this->status);
+ $object->statusLabel = $this->LibStatut(intval($this->status), 1);
+ $object->contactUsersAffected = $this->liste_contact(-1,'internal',1);
+
+ $object->fk_scrum_user_story_sprint = $this->fk_scrum_user_story_sprint;
+ $object->fk_scrum_user_story_sprint= $this->fk_scrum_user_story_sprint;
+ $object->qty_planned = doubleval($this->qty_planned);
+ $object->qty_consumed = doubleval($this->qty_consumed);
+
+ $this->calcTimeTaskPlanned();
+ $object->qty_task_planned = doubleval($this->qty_task_planned);
+
+ $object->qty_remain_for_split = 0;
+ $qtyConsumeBase = max($this->qty_task_planned, $this->qty_consumed);
+ if($this->qty_planned - $qtyConsumeBase > 0){
+ $object->qty_remain_for_split = $this->qty_planned - $qtyConsumeBase;
+ }
+
+
+ return $object;
+ }
+
+
+
+ /**
+ * Permet de spliter l'us carte en scrum task
+ * @param double $qty la quantité de la nouvelle carte
+ * @param string $newCardLabel le libelle de la nouvelle carte
+ * @param ScrumCard $scrumCard
+ * @return bool
+ */
+ public function splitCard($qty, $newCardLabel, ScrumCard $scrumCard, User $user ){
+
+ $qty = doubleval($qty);
+
+ if(!class_exists('ScrumTask')){
+ require_once __DIR__ . '/scrumtask.class.php';
+ }
+ if(!class_exists('ScrumCard')){
+ require_once __DIR__ . '/scrumcard.class.php';
+ }
+
+ $this->calcTimeTaskPlanned();
+
+ // Vérification de la liaison entre ScrumCard et ScrumTask
+ if($scrumCard->element_type != $this->element || $scrumCard->fk_element != $this->id ){
+ $this->error = 'Error : scrum card not linked';
+ $this->errors[] = $this->error;
+ return false;
+ }
+
+
+ // Vérification du temps restant
+ if($qty > $this->qty_planned - $this->qty_task_planned ){
+ $this->error = 'Too much quantity';
+ $this->errors[] = $this->error;
+ return false;
+ }
+
+ // Ajout de la nouvelle ScrumTask
+ $newScrumTask = new ScrumTask($this->db);
+ $newScrumTask->fk_scrum_user_story_sprint = $this->id;
+ $newScrumTask->description = $this->description;
+
+ $newScrumTask->qty_planned = $qty;
+ $newScrumTask->label = $newCardLabel;
+ if(empty($newCardLabel) || is_array($newCardLabel)){ $newScrumTask->label = $this->label;}
+
+ $resCreate = $newScrumTask->create($user);
+ if($resCreate<0){
+ $this->error = $newScrumTask->error;
+ $this->errors = array_merge($this->errors, $newScrumTask->errors);
+ return false;
+ }
+
+ // MISE A JOUR DE LA SCRUM TASK QUE L'ON SPLIT
+ $this->qty_task_planned-= $qty;
+
+// Bloc deja effectué par $newScrumTask->create
+// // AJOUT DE LA CARD LIÉE
+// $newScrumCard = new ScrumCard($this->db);
+// if(empty($newCardLabel)){
+// $newScrumCard->label = $this->label;
+// }
+// $newScrumCard->label = $newScrumTask->label;
+// $newScrumCard->fk_element = $newScrumTask->id;
+// $newScrumCard->element_type = $newScrumTask->element;
+// $newScrumCard->fk_scrum_kanbanlist = $scrumCard->fk_scrum_kanbanlist;
+// $newScrumCard->fk_rank = $scrumCard->fk_rank;
+// $res = $newScrumCard->create($user);
+// if($res<=0){
+// $this->error = 'Error creating ScrumCard : '.$newScrumCard->error;
+// $this->errors = array_merge($this->errors, $newScrumCard->errors);
+// return false;
+// }
+
+ return true;
+ }
+
/**
* Initialise object with example values
* Id must be 0 if object instance is a specimen
@@ -1188,6 +1308,24 @@ public function calcTimeSpent(){
return 0;
}
+ /**
+ *
+ * @return int
+ */
+ public function calcTimeTaskPlanned(){
+
+ $sql = /** @lang MySQL */ "SELECT SUM(qty_planned) sumTaskPlanned FROM ".MAIN_DB_PREFIX."scrumproject_scrumtask "
+ ." WHERE fk_scrum_user_story_sprint = ".intval($this->id);
+
+ $obj = $this->db->getRow($sql);
+ if($obj){
+ $this->qty_task_planned = doubleval($obj->sumTaskPlanned);
+ return $this->qty_task_planned;
+ }
+
+ return 0;
+ }
+
/**
* @param User $user
* @param $notrigger
diff --git a/core/modules/modScrumProject.class.php b/core/modules/modScrumProject.class.php
index de8ba43bd9a05..bfd8659acd80a 100644
--- a/core/modules/modScrumProject.class.php
+++ b/core/modules/modScrumProject.class.php
@@ -64,7 +64,7 @@ public function __construct($db)
$this->editor_name = 'ATM Consulting';
$this->editor_url = 'www.atm-consulting.fr';
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'
- $this->version = '1.0.9';
+ $this->version = '1.1.0';
// Url to the file with your last numberversion of this module
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
diff --git a/css/kanban.css b/css/kanban.css
index 478b3279bd010..f3932d4001ba6 100644
--- a/css/kanban.css
+++ b/css/kanban.css
@@ -96,7 +96,153 @@ dialog.kanban-dialog[open]{
}
+/* Dialog content */
+.dialog-form-head{
+ font-size: 0.8em;
+}
+
+.dialog-form-head-item:not(:first-child){
+ margin-left: 30px;
+}
+
+.dialog-form-head-item.split-qty-remain{
+ font-weight: bold;
+}
+
+.dialog-form-body{
+ margin-top: 10px;
+}
+
+
+.dialog-form-control{
+ margin-top: var(--dialog-padding);
+}
+
+.curent-split-item-line{
+
+}
+.new-split-item-line{
+ border-top: 1px solid rgba(0,0,0,0.1);
+}
+
+.dialog-form-icon-btn{
+
+ --bg-gradian-start: #ffffff;
+ --bg-gradian-end: #e6e6e6;
+ --border-color: #aaa;
+ --colortext: #444;
+
+ margin-bottom: 3px;
+ margin-top: 3px;
+ margin-left: 5px;
+ margin-right: 5px;
+ display: inline-block;
+ padding: 3px 8px;
+ text-align: center;
+ cursor: pointer;
+ text-decoration: none !important;
+ background-color: var(--bg-gradian-end);
+ background-image: -moz-linear-gradient(top,var(--bg-gradian-start), var(--bg-gradian-end));
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(var(--bg-gradian-start)), to(var(--bg-gradian-end)));
+ background-image: -webkit-linear-gradient(top, var(--bg-gradian-start), var(--bg-gradian-end));
+ background-image: -o-linear-gradient(top, var(--bg-gradian-start), var(--bg-gradian-end));
+ background-image: linear-gradient(to bottom, var(--bg-gradian-start), var(--bg-gradian-end));
+ background-repeat: repeat-x;
+ border: 1px solid var(--border-color);
+ -webkit-border-radius: 2px;
+ border-radius: 1px;
+ font-weight: bold;
+ text-transform: uppercase;
+
+
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+ /*
+ Introduced in Internet Explorer 10.
+ See http://ie.microsoft.com/testdrive/HTML5/msUserSelect/
+ */
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.dialog-form-icon-btn:active{
+ --bg-gradian-start: #e6e6e6;
+ --bg-gradian-end: #ffffff;
+}
+
+html[data-theme-color-scheme="dark"] .dialog-form-icon-btn{
+ --bg-gradian-start: rgb(44, 55, 70);
+ --bg-gradian-end: var(--bg-gradian-start);
+ --colortext: var(--general-text-color);
+ --border-color: var(--bg-gradian-start);
+}
+html[data-theme-color-scheme="dark"] .dialog-form-icon-btn:active{
+ --bg-gradian-start: rgb(26, 35, 42);
+}
+
+
+/* Line separation */
+hr.dialog-separator {
+
+ --border-color : rgba(0,0,0,0.2);
+
+ border: none;
+ overflow: visible;
+ box-sizing: content-box;
+ order: 0;
+ height: 1px;
+ width: 10%;
+ position: relative;
+ margin: 10px auto;
+
+ background: var(--border-color);
+}
+hr.dialog-separator:before {
+ content: "";
+ width: 4px;
+ height: 4px;
+ background: #fff;
+ display: inline-block;
+ border: 1px solid var(--border-color);
+ position: absolute;
+ top: -3px;/* un petit fallback au cas ou la virgule en css passe pas*/
+ top: -2.5px;
+ left: 50%;
+ margin: 0 0 0 -3px;
+ transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ /* IE 9 */
+ -webkit-transform: rotate(45deg);
+ /* Opera, Chrome, and Safari */
+}
+
+.dialog-form-head-number{
+ min-width: 35px;
+ display: inline-block;
+}
+
+.dialog-form-item{
+ display: inline-block;
+}
+.dialog-form-item [readonly]{
+ --inputbackgroundcolor: #efefef;
+}
+
+
+html[data-theme-color-scheme="dark"] .dialog-form-item [readonly]{
+ --inputbackgroundcolor: #535c6a;
+ --colortext: #8e96a5;
+}
+
+.split-qty-planned{
+ width: 90px;
+}
+
+.split-item-label{
+ width: 600px;
+}
html[data-theme-color-scheme="dark"] dialog.kanban-dialog{
@@ -138,7 +284,6 @@ button.kanban-btn {
-webkit-user-select: none;
touch-action: manipulation;
}
-
button.kanban-btn[data-btn-role="accept"]{
font-weight: bold;
--button-background-color : var(--butactionbg);
@@ -152,6 +297,12 @@ button.kanban-btn[data-btn-role="accept"]:hover{
filter: hue-rotate(5deg);
}
+button.kanban-btn[disabled]{
+ opacity: 0.3;
+ cursor: not-allowed;
+}
+
+
button.kanban-btn[data-btn-role="cancel"]{
--button-background-color : rgba(51, 51, 51, 0);
--button-color : #595959;
@@ -909,6 +1060,11 @@ html[data-theme-color-scheme="dark"]{
color: var(--general-text-color);
}
+html[data-theme-color-scheme="dark"] input{
+ --inputbackgroundcolor: #4c5666;
+ --colortext:#ffffff;
+}
+
html[data-theme-color-scheme="dark"] a:link, html[data-theme-color-scheme="dark"] a:visited{
color: #1c8ee7;
}
diff --git a/interface-kanban.php b/interface-kanban.php
index 67719f4d28464..a5d5d284b950a 100644
--- a/interface-kanban.php
+++ b/interface-kanban.php
@@ -67,6 +67,12 @@
elseif ($action === 'getAllItemToList') {
_actionAddItemToList($jsonResponse);
}
+elseif ($action === 'getScrumCardData') {
+ _actionGetScrumCardData($jsonResponse);
+}
+elseif ($action === 'splitScrumCard') {
+ _actionSplitScrumCard($jsonResponse);
+}
elseif ($action === 'dropItemToList') {
_actionDropItemToList($jsonResponse);
}
@@ -372,12 +378,41 @@ function _actionAddItemToList($jsonResponse){
}
}
+
+/**
+ * @param JsonResponse $jsonResponse
+ * @return bool|void
+ */
+function _actionGetScrumCardData($jsonResponse){
+ global $db;
+
+ $data = GETPOST("data", "array");
+
+ // check kanban list data
+ if(empty($data['id'])){
+ $jsonResponse->msg = 'Need scrumcard Id';
+ return false;
+ }
+
+ $scrumCard = new ScrumCard($db);
+ $res = $scrumCard->fetch($data['id']);
+ if($res <= 0){
+ $jsonResponse->msg = 'Scrumcard fetch error';
+ return false;
+ }
+
+ $jsonResponse->result = 1;
+ $jsonResponse->data = $scrumCard->getScrumKanBanItemObjectStd();
+ return true;
+}
+
+
/**
* @param JsonResponse $jsonResponse
* @return bool|void
*/
function _actionDropItemToList($jsonResponse){
- global $user, $langs, $db;
+ global $langs, $db;
$data = GETPOST("data", "array");
@@ -641,6 +676,67 @@ function _checkObjectByElement($elementType, $id, $jsonResponse){
}
+/**
+ * @param JsonResponse $jsonResponse
+ * @return bool|CommonObject
+ */
+function _actionSplitScrumCard($jsonResponse){
+ global $langs, $db, $user;
+
+
+ $data = GETPOST("data", "array");
+
+ if(empty($data['id'])){
+ $jsonResponse->msg = 'Need card Id';
+ return false;
+ }
+
+ $scrumCard = new ScrumCard($db);
+ if($scrumCard->fetch($data['id']) <= 0){
+ $jsonResponse->msg = $langs->trans('RequireValidExistingElement');
+ return false;
+ }
+
+ $errors = 0;
+
+ if(empty($data['form']) || empty($data['form']['new-item-qty-planned'])){
+ $jsonResponse->msg = $langs->trans('RequireValidSplitData');
+ return false;
+ }
+
+ if(!is_array($data['form']['new-item-qty-planned'])){
+ $data['form']['new-item-qty-planned'] = array(
+ $data['form']['new-item-qty-planned']
+ );
+ }
+
+ if(!is_array($data['form']['new-item-label'])){
+ $data['form']['new-item-label'] = array(
+ $data['form']['new-item-label']
+ );
+ }
+
+ foreach ($data['form']['new-item-qty-planned'] as $key => $qty){
+ $newCardLabel = '';
+ if(!empty($data['form']['new-item-label'][$key])){
+ $newCardLabel = $data['form']['new-item-label'][$key];
+ }
+
+ if(is_array($newCardLabel)){ $newCardLabel = '';}
+
+ $res = $scrumCard->splitCard($qty, $newCardLabel, $user);
+ if($res<=0){
+ $jsonResponse->msg = $scrumCard->errorsToString();
+ $errors++;
+ }
+ }
+
+
+
+ return $errors==0;
+}
+
+
/**
* @param JsonResponse $jsonResponse
* @param int|bool $userId
diff --git a/js/dialog.js b/js/dialog.js
index ba2a3ff0bfb56..4652f1f1c5f71 100644
--- a/js/dialog.js
+++ b/js/dialog.js
@@ -16,6 +16,9 @@ class Dialog {
title: '',
dialogClass: '',
content: '',
+ onClose : function (){ return true; },
+ onOpen : function (){ return true; },
+ onAccept : function (){ return true; },
template: '