From f0ed77dcd5fd62e5f4aeec42b23fc0cd77e8f2cd Mon Sep 17 00:00:00 2001 From: Francisco Junior <93009549+AnotherOne07@users.noreply.github.com> Date: Fri, 26 Apr 2024 16:47:18 -0300 Subject: [PATCH] [TCDA-232] Fix/lunch meal portion (#669) * fix/select now shows food values * fix:modal updated and necessary API routes created * fix/lunch meal controller adjusted * fix/model updated, database adjusted but still missing controller fixes * fix/change in render partial params * fix/some forms are already working * fix/form and action finished * fix/remove unnecessary comments * CHANGELOG updated * fix/sonarlint fixes * fix(lunch): Corrigindo comando sql da migration --------- Co-authored-by: TI GUSTAVO Co-authored-by: Gustavo Santos --- CHANGELOG.md | 3 +- .../2024-03-27_lunch_meal_portion/sql.sql | 21 +++ .../lunch/controllers/LunchController.php | 113 +++++++++---- app/modules/lunch/models/MenuMeal.php | 54 +++--- app/modules/lunch/models/Portion.php | 95 ++++++----- .../lunch/resources/common/js/lunch.js | 49 +++++- themes/default/views/lunch/lunch/_form.php | 159 ++++++++---------- themes/default/views/lunch/lunch/update.php | 1 + 8 files changed, 295 insertions(+), 200 deletions(-) create mode 100644 app/migrations/2024-03-27_lunch_meal_portion/sql.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index de7bb5495..9ee61a7c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,8 @@ - Correção no conteúdo ministrado em sala de aula ## [Versão 3.76.129] -- Correção na descrição da séries para as inconsistências sagres +- Corrigir a funcionalidade de cadastrar porções em refeições de cardápio +- Ajustar banco de dados para adequar ao novo fluxo da tela de atualizar cardápio ## [Versão 3.76.128] - Corrigido erro que não mostrava o nome da escola e das turmas nas inconsistências sagres diff --git a/app/migrations/2024-03-27_lunch_meal_portion/sql.sql b/app/migrations/2024-03-27_lunch_meal_portion/sql.sql new file mode 100644 index 000000000..cc61af9e4 --- /dev/null +++ b/app/migrations/2024-03-27_lunch_meal_portion/sql.sql @@ -0,0 +1,21 @@ +ALTER TABLE lunch_portion +ADD COLUMN food_fk INT NOT NULL; + +ALTER TABLE lunch_portion +ADD CONSTRAINT fk_lunch_portion_food +FOREIGN KEY (food_fk) REFERENCES food(id); + +ALTER TABLE lunch_portion +DROP FOREIGN KEY portion_unity; + +ALTER TABLE lunch_portion +ADD CONSTRAINT fk_lunch_unity_fk +FOREIGN KEY (unity_fk) REFERENCES food_measurement(id); + + +ALTER TABLE lunch_portion +DROP FOREIGN KEY portion_item; + +ALTER TABLE lunch_portion DROP COLUMN item_fk; + +ALTER TABLE lunch_menu_meal DROP COLUMN amount; diff --git a/app/modules/lunch/controllers/LunchController.php b/app/modules/lunch/controllers/LunchController.php index 910751503..3fe5ab4e2 100755 --- a/app/modules/lunch/controllers/LunchController.php +++ b/app/modules/lunch/controllers/LunchController.php @@ -1,5 +1,6 @@ getPost("Menu", false); $menu = Menu::model()->findByPk($id); + $menuMeals = MenuMeal::model()->findAllByAttributes(array("menu_fk" => $menu->id)); + $meals = []; + foreach($menuMeals as $menuMeal) + { + // Array temporário para inserir porções de uma refeição + $tmpPortions = []; + // Encontrar todas as porções que pertencem à uma refeição + $mealsPortion = MealPortion::model()->findAllByAttributes(array("meal_fk" => $menuMeal->id)); + + // Inserir porções em array temporário + foreach($mealsPortion as $mealPortion){ + array_push($tmpPortions, Portion::model()->findByPk($mealPortion->portion_fk)); + } + + // Inserir par Refeição:Porções em array Refeições + array_push( + $meals, + [ + "meal" => Meal::model()->findByPk($menuMeal->meal_fk), + "portions" => $tmpPortions + ] + ); + } if($menuPost){ $menu->name = $menuPost['name']; @@ -65,7 +89,7 @@ public function actionUpdate($id){ $this->render('update', ["menu" => $menu]); } }else { - $this->render('update', ["menu" => $menu]); + $this->render('update', ["menu" => $menu, "meals" => $meals]); } } public function actionLunchDelete(){ @@ -78,23 +102,13 @@ public function actionRemovePortion(){ /* @var $mealPortion MealPortion */ $request = Yii::app()->getRequest(); - $menuPost = $request->getPost("Menu", false); - $mealPortionPost = $request->getPost("MealPortion", false); - $amountPost = $mealPortionPost['amount'] > 0 ? -1 *$mealPortionPost['amount'] : $mealPortionPost['amount']; - - $mealPortion = MealPortion::model()->findByPk($mealPortionPost['id']); - if(isset($mealPortion)){ - $amount = $mealPortion->amount; - if($amount + $amountPost > 0){ - $mealPortion->amount = $amount + $amountPost; - if($mealPortion->validate()){ - $mealPortion->save(); - Yii::app()->user->setFlash('success', Yii::t('lunchModule.lunch', 'Portion decreased successfully!')); - }else{ - Yii::app()->user->setFlash('error', Yii::t('lunchModule.lunch', 'Error when removing portion.')); - } - }else{ - $mealPortion->delete(); + $portionId = $request->getPost("id", false); + $menuPost = $request->getPost("menu", false); + + $portion = Portion::model()->findByPk($portionId); + $mealPortion = MealPortion::model()->findByAttributes(["portion_fk" => $portion->id]); + if(isset($portion) && isset($mealPortion)){ + if($mealPortion->delete() && $portion->delete()){ Yii::app()->user->setFlash('success', Yii::t('lunchModule.lunch', 'Portion removed successfully!')); } }else{ @@ -103,21 +117,56 @@ public function actionRemovePortion(){ $this->redirect(yii::app()->createUrl('lunch/lunch/update',["id"=>$menuPost['id']])); } + public function actionGetFoodAlias() + { + $criteria = new CDbCriteria(); + $criteria->select = 'id, description, measurementUnit'; + $criteria->condition = 'alias_id = t.id'; + + $foods_description = Food::model()->findAll($criteria); + + return $foods_description; + } + + public function actionGetFoodMeasurement() + { + $foodMeasurements = FoodMeasurement::model()->findAll(); + $options = array(); + foreach ($foodMeasurements as $foodMeasurement) { + array_push( + $options, + array( + "id" => $foodMeasurement->id, + "unit" => $foodMeasurement->unit, + "value" => $foodMeasurement->value, + "measure" => $foodMeasurement->measure + ) + ); + } + return $options; + } + + public function actionGetUnityMeasure() + { + $measureId = Yii::app()->request->getPost('id'); + $modal = FoodMeasurement::model()->findByPk($measureId); + + echo CJSON::encode($modal); + } + public function actionAddPortion(){ /* @var $mealPortion MealPortion */ /* @var $portion Portion */ $request = Yii::app()->getRequest(); $menuPost = $request->getPost("Menu", false); - $portionPost = $request->getPost("Portion", false); $mealPortionPost = $request->getPost("MealPortion", false); + + $isNewPortion = false; - if($portionPost){ + if($mealPortionPost){ $portion = new Portion(); - $portion->item_fk = $portionPost["item_fk"]; - $portion->measure = $portionPost["measure"]; - $portion->unity_fk = $portionPost["unity_fk"]; - $portion->amount = 1; + $portion->setAttributes($mealPortionPost); if($portion->validate()){ $portion->save(); $isNewPortion = true; @@ -128,8 +177,8 @@ public function actionAddPortion(){ } $mealId = $mealPortionPost["meal_fk"]; - $portionId = $isNewPortion ? $portion->id : $mealPortionPost["portion_fk"]; - $mealPortion = MealPortion::model()->findByAttributes(["meal_fk" => $mealId, "portion_fk"=>$portionId]); + $portionId = $portion->id; + $mealPortion = MealPortion::model()->findByAttributes(["meal_fk" => $mealId, "portion_fk" => $portionId]); $isNewMealPortion = !isset($mealPortion); if($isNewMealPortion){ @@ -137,8 +186,6 @@ public function actionAddPortion(){ $mealPortion->meal_fk = $mealId; $mealPortion->portion_fk = $portionId; $mealPortion->amount = $mealPortionPost["amount"]; - }else{ - $mealPortion->amount = $mealPortion->amount + $mealPortionPost["amount"]; } if($mealPortion->validate()){ @@ -172,7 +219,6 @@ public function actionAddMeal(){ $menuMeal = new MenuMeal(); $menuMeal->meal_fk = $meal->id; $menuMeal->menu_fk = $menuMealPost['menu_fk']; - $menuMeal->amount = $menuMealPost['amount']; if($menuMeal->validate()){ $menuMeal->save(); @@ -201,14 +247,13 @@ public function actionChangeMeal(){ if($mealPost && $menuMealPost) { $mealId = $menuMealPost['meal_fk']; $menuId = $menuMealPost['menu_fk']; - $amount = $menuMealPost['amount']; $restrictions = $mealPost['restrictions']; $menuMeal = MenuMeal::model()->findByAttributes(['meal_fk'=>$mealId, 'menu_fk'=>$menuId]); - $menuMeal->amount = $amount; - $menuMeal->meal->restrictions = $restrictions; - if($menuMeal->meal->validate() && $menuMeal->validate()) { - $menuMeal->meal->save(); + $meal = Meal::model()->findByPk($menuMeal->meal_fk); + $meal->restrictions = $restrictions; + if($meal->validate() && $menuMeal->validate()) { + $meal->save(); $menuMeal->save(); Log::model()->saveAction("lunch_meal", $menuMeal->id, "U", $menuMeal->menu->name); Yii::app()->user->setFlash('success', Yii::t('lunchModule.lunch', 'Meal updated successfully!')); diff --git a/app/modules/lunch/models/MenuMeal.php b/app/modules/lunch/models/MenuMeal.php index 14f178684..7684c18b3 100755 --- a/app/modules/lunch/models/MenuMeal.php +++ b/app/modules/lunch/models/MenuMeal.php @@ -7,24 +7,13 @@ * @property integer $id * @property integer $menu_fk * @property integer $meal_fk - * @property double $amount * * The followings are the available model relations: - * @property Menu $menu - * @property Meal $meal + * @property Menu $menuFk + * @property Meal $mealFk */ class MenuMeal extends CActiveRecord { - /** - * Returns the static model of the specified AR class. - * @param string $className active record class name. - * @return MenuMeal the static model class - */ - public static function model($className=__CLASS__) - { - return parent::model($className); - } - /** * @return string the associated database table name */ @@ -41,12 +30,11 @@ public function rules() // NOTE: you should only define rules for those attributes that // will receive user inputs. return array( - array('menu_fk, meal_fk, amount', 'required'), + array('menu_fk, meal_fk', 'required'), array('menu_fk, meal_fk', 'numerical', 'integerOnly'=>true), - array('amount', 'numerical'), // The following rule is used by search(). - // Please remove those attributes that should not be searched. - array('id, menu_fk, meal_fk, amount', 'safe', 'on'=>'search'), + // @todo Please remove those attributes that should not be searched. + array('id, menu_fk, meal_fk', 'safe', 'on'=>'search'), ); } @@ -69,31 +57,47 @@ public function relations() public function attributeLabels() { return array( - 'id' => Yii::t('lunchModule.labels', 'ID'), - 'menu_fk' => Yii::t('lunchModule.labels', 'Menu'), + 'id' => 'ID', + 'menu_fk' => Yii::t('lunchModule.labels', 'Menu'), 'meal_fk' => Yii::t('lunchModule.labels', 'Meal'), - 'amount' => Yii::t('lunchModule.labels', 'Amount'), ); } /** * Retrieves a list of models based on the current search/filter conditions. - * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions. + * + * Typical usecase: + * - Initialize the model fields with values from filter form. + * - Execute this method to get CActiveDataProvider instance which will filter + * models according to data in model fields. + * - Pass data provider to CGridView, CListView or any similar widget. + * + * @return CActiveDataProvider the data provider that can return the models + * based on the search/filter conditions. */ public function search() { - // Warning: Please modify the following code to remove attributes that - // should not be searched. + // @todo Please modify the following code to remove attributes that should not be searched. $criteria=new CDbCriteria; $criteria->compare('id',$this->id); $criteria->compare('menu_fk',$this->menu_fk); $criteria->compare('meal_fk',$this->meal_fk); - $criteria->compare('amount',$this->amount); return new CActiveDataProvider($this, array( 'criteria'=>$criteria, )); } -} \ No newline at end of file + + /** + * Returns the static model of the specified AR class. + * Please note that you should have this exact method in all your CActiveRecord descendants! + * @param string $className active record class name. + * @return MenuMeal the static model class + */ + public static function model($className=__CLASS__) + { + return parent::model($className); + } +} diff --git a/app/modules/lunch/models/Portion.php b/app/modules/lunch/models/Portion.php index 4bb456ab0..ccc68342c 100755 --- a/app/modules/lunch/models/Portion.php +++ b/app/modules/lunch/models/Portion.php @@ -5,101 +5,108 @@ * * The followings are the available columns in table 'lunch_portion': * @property integer $id - * @property integer $item_fk * @property integer $amount * @property integer $unity_fk * @property double $measure + * @property integer $food_fk * * The followings are the available model relations: - * @property MealPortion[] $mealPortions - * @property Item $item - * @property Unity $unity + * @property LunchMealPortion[] $lunchMealPortions + * @property Food $foodFk + * @property FoodMeasurement $unityFk */ -class Portion extends CActiveRecord{ - /** - * Returns the static model of the specified AR class. - * @param string $className active record class name. - * @return Portion the static model class - */ - public static function model($className=__CLASS__){ - return parent::model($className); - } - +class Portion extends CActiveRecord +{ /** * @return string the associated database table name */ - public function tableName(){ + public function tableName() + { return 'lunch_portion'; } - /** - * Get the item name with the measure - * @return String the item name with the measure - */ - public function getConcatName(){ - return $this->item->name . " (". $this->measure.$this->unity->acronym.")"; - } - /** * @return array validation rules for model attributes. */ - public function rules(){ + public function rules() + { // NOTE: you should only define rules for those attributes that // will receive user inputs. return array( - array('item_fk, amount, unity_fk, measure', 'required'), - array('item_fk, amount, unity_fk', 'numerical', 'integerOnly'=>true), + array('amount, unity_fk, measure, food_fk', 'required'), + array('amount, unity_fk, food_fk', 'numerical', 'integerOnly'=>true), array('measure', 'numerical'), // The following rule is used by search(). - // Please remove those attributes that should not be searched. - array('id, item_fk, amount, unity_fk, measure', 'safe', 'on'=>'search'), + // @todo Please remove those attributes that should not be searched. + array('id, amount, unity_fk, measure, food_fk', 'safe', 'on'=>'search'), ); } /** * @return array relational rules. */ - public function relations(){ + public function relations() + { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( - 'mealPortions' => array(self::HAS_MANY, 'MealPortion', 'portion_fk'), - 'item' => array(self::BELONGS_TO, 'Item', 'item_fk'), - 'unity' => array(self::BELONGS_TO, 'Unity', 'unity_fk'), + 'lunchMealPortions' => array(self::HAS_MANY, 'LunchMealPortion', 'portion_fk'), + 'foodFk' => array(self::BELONGS_TO, 'Food', 'food_fk'), + 'unityFk' => array(self::BELONGS_TO, 'FoodMeasurement', 'unity_fk'), ); } /** * @return array customized attribute labels (name=>label) */ - public function attributeLabels(){ + public function attributeLabels() + { return array( - 'id' => Yii::t('lunchModule.labels', 'ID'), - 'item_fk' => Yii::t('lunchModule.labels', 'Item'), - 'amount' => Yii::t('lunchModule.labels', 'Amount'), - 'unity_fk' => Yii::t('lunchModule.labels', 'Unity'), - 'measure' => Yii::t('lunchModule.labels', 'Measure'), + 'id' => 'ID', + 'amount' => 'Amount', + 'unity_fk' => 'Unity Fk', + 'measure' => 'Measure', + 'food_fk' => 'Food Fk', ); } /** * Retrieves a list of models based on the current search/filter conditions. - * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions. + * + * Typical usecase: + * - Initialize the model fields with values from filter form. + * - Execute this method to get CActiveDataProvider instance which will filter + * models according to data in model fields. + * - Pass data provider to CGridView, CListView or any similar widget. + * + * @return CActiveDataProvider the data provider that can return the models + * based on the search/filter conditions. */ - public function search(){ - // Warning: Please modify the following code to remove attributes that - // should not be searched. + public function search() + { + // @todo Please modify the following code to remove attributes that should not be searched. $criteria=new CDbCriteria; $criteria->compare('id',$this->id); - $criteria->compare('item_fk',$this->item_fk); $criteria->compare('amount',$this->amount); $criteria->compare('unity_fk',$this->unity_fk); $criteria->compare('measure',$this->measure); + $criteria->compare('food_fk',$this->food_fk); return new CActiveDataProvider($this, array( 'criteria'=>$criteria, )); } -} \ No newline at end of file + + /** + * Returns the static model of the specified AR class. + * Please note that you should have this exact method in all your CActiveRecord descendants! + * @param string $className active record class name. + * @return Portion the static model class + */ + public static function model($className=__CLASS__) + { + return parent::model($className); + } +} diff --git a/app/modules/lunch/resources/common/js/lunch.js b/app/modules/lunch/resources/common/js/lunch.js index 8ce8c9ebb..b57310c32 100755 --- a/app/modules/lunch/resources/common/js/lunch.js +++ b/app/modules/lunch/resources/common/js/lunch.js @@ -4,14 +4,21 @@ $(document).on('click', '.button-add-portion', function () { var mealId = button.data('meal-id'); modal.find('#meal-id').val(mealId); + updateMeasureAmount($('#unityDropdown')); }); $(document).on('click', '.button-remove-portion', function () { var button = $(this); - var modal = $("#removePortion"); - var mealPortionId = button.data('meal-portion-id'); - - modal.find('#meal-portion-id').val(mealPortionId); + $.ajax({ + url: "?r=lunch/lunch/removePortion", + type: "POST", + data: { + menu: button.data('menu-id'), + id: button.data('meal-portion-id') + } + }).success(function(data){ + location.reload(); + }) }); @@ -43,13 +50,45 @@ $(document).on('click', '.button-remove-lunch', function () { }); - $(document).on("show.bs.modal", "#addPortion", function(){ $('#is-add-amount').show().children().find("input, select").prop('disabled', false); $('#is-new-portion').hide().children().find("input, select").prop('disabled', true); + }); $(document).on('click', '#new-portion', function(){ $('#is-add-amount').hide().children().find("input, select").prop('disabled', true); $('#is-new-portion').show().children().find("input, select").prop('disabled', false); }); + +$(document).ready(function(){ + $(document).on('change', "#unityDropdown", function(){ + updateMeasureAmount($(this)); + }) +}) + +$(document).ready(function(){ + $(document).on('change', '#foodAmount', function () { + updateMeasureAmount($('#unityDropdown')); + }) +}) + +function updateMeasureAmount(select){ + let unityMeasure = select.val(); + $.ajax({ + url: "?r=lunch/lunch/getUnityMeasure", + type: "POST", + data: { + id: unityMeasure + } + }).success(function(data) { + data = JSON.parse(data); + const amountUnity = $('#foodAmount').val(); + const totalAmount = amountUnity * data.value; + const txt = `${totalAmount} ${data.measure}`; + $(txt).replaceAll("#lunchUnityMeasure span"); + + const measureInput = $('#measureInput'); + measureInput.val(totalAmount); + }); +} diff --git a/themes/default/views/lunch/lunch/_form.php b/themes/default/views/lunch/lunch/_form.php index b88c5d18e..7289d6a1e 100755 --- a/themes/default/views/lunch/lunch/_form.php +++ b/themes/default/views/lunch/lunch/_form.php @@ -1,9 +1,13 @@ controller->module->baseScriptUrl; $cs = Yii::app()->getClientScript(); @@ -101,15 +105,15 @@ Código Restrições Porções - Quantidade Ações menuMeals as $menuMeal) : - $meal = $menuMeal->meal; + foreach ($meals as $meal) : + $portions = $meal["portions"]; + $meal = $meal["meal"]; $odd = !$odd; ?> "> @@ -118,15 +122,28 @@ - mealPortions as $mealPortion) : - $portion = $mealPortion->portion ?> + findByPk($portion->food_fk); + $foodAlias = $lunchController->actionGetFoodAlias(); + $food = array_filter($foodAlias, + function($f) use ($foodModel) {return $f->id == $foodModel->id;}); + $foodUnity = FoodMeasurement::model()->findByPk($portion->unity_fk); + $food = array_pop($food); ?> "> - - + + @@ -134,8 +151,7 @@
item->name ?>amount) . "x " . - floatval($portion->measure)). " " . - $portion->unity->acronym ?>description ?>amount) . " " . $foodUnity->unit . " x " . + floatval($foodUnity->value)). " " . + $foodUnity->measure ?> - +
"> - - + @@ -144,9 +160,8 @@
- amount ?> - + @@ -183,77 +198,51 @@
-
+
- 'control-label')); ?> -
- findAll(), 'id', 'concatName'), - ['class' => 'span12'] - ); ?> -
-
-
- -
- - Adicionar Novo Item - + 'control-label')); ?> +
+ init(); + echo CHtml::dropDownList( + 'MealPortion[food_fk]', + '', + CHtml::listData($lunchController->actionGetFoodAlias(), 'id', 'description'), + ); + ?>
-
-
- 'control-label', 'style' => 'width: 100%')); ?> -
- '0', 'step' => '1', 'class' => 'span10', 'style' => 'height:44px;width:100%;']); ?> -
-
-
-
-
-
-
-

- -

-
-
-
-
- 'control-label')); ?> -
- with(["inventories" => ["select" => "amount", 'condition' => 'amount > 0']])->findAll(), 'id', 'concatName'), - ['class' => 'pull-left span10', 'style' => 'height:44px;width:100%;'] - ); ?> - -
-
-
- 'control-label')); ?> -
- '0', 'step' => '1', 'class' => 'span10', 'style' => 'height:44px;width:100%;']); ?> + 'control-label')); ?> +
+ actionGetFoodMeasurement(), 'id', 'unit'), + array('id' => 'unityDropdown') + ); + ?>
-
- 'control-label')); ?> -
- '0', 'step' => '1', 'class' => 'span10', 'style' => 'height:44px;width:100%;']); ?> +
+
+ 'control-label', 'style' => 'width: 100%')); ?> +
+ '0', 'step' => '1', 'class' => 'span10', + 'style' => 'height:44px;width:100%;', + 'id' => 'foodAmount']); + ?> +
-
-
- 'control-label', 'style' => 'width:auto')); ?> -
- findAll(['order' => 'acronym']), 'id', 'acronym'), - ['class' => ' span10', 'style' => 'width:100%'] - ); ?> +
+ 'control-label', 'style' => 'width: 100%')); ?> + 'hide', + 'id' => 'measureInput' + ]); ?> +
@@ -342,12 +331,6 @@ 'resize: vertical;', 'class' => 'span10', 'style' => 'height:44px;width: 100%']); ?>
-
- 'control-label')); ?> -
- '1', 'step' => '1', 'class' => 'span10', 'style' => 'height:44px; width:99%;']); ?> -
-
@@ -391,12 +374,6 @@ 'resize: vertical;', 'class' => 'span10', 'style' => 'height:44px;width: 100%']); ?>
-
- 'control-label')); ?> -
- '1', 'step' => '1', 'class' => 'span10', 'style' => 'height:44px; width:99%;']); ?> -
-
diff --git a/themes/default/views/lunch/lunch/update.php b/themes/default/views/lunch/lunch/update.php index e7b0c9ed6..b695031c4 100755 --- a/themes/default/views/lunch/lunch/update.php +++ b/themes/default/views/lunch/lunch/update.php @@ -22,6 +22,7 @@
renderPartial('_form', array( 'menuModel' => $menu, + 'meals' => $meals, 'title' => $title, 'isUpdate'=>true ));