Formulário Master - Detail (Ordem De Compras)

Pessoal, bom dia à todos.

Estou desenvolvendo um sistema de Gerenciamento Comercial (Contas a pagar, receber, compras, vendas, estoque) para uso próprio. Pesquisei várias opções no mercado, mas todas ficavam acima do meu orçamento. Portanto, resolvi criar coragem e desenvolver eu mesmo.

O problema é que apesar de trabalhar com informática desde 1995, eu nunca fui programador Web. Então estou começando tudo do zero, pesquisando bastante nas documentações e fóruns sobre o assunto.

Agora preciso aprender a criar formulários Master/Detail. Vou começar pela Ordem de Compras, mas vou utilizar isso em diversas situações.

No meu caso, tenho uma tabela MASTER (CABEÇALHO DE COMPRA) e a DETAIL (ITENS DE COMPRA).

Achei algumas informações sobre isso, mas nenhuma tão didática para um leigo como eu.

Não consegui inserir os links (pois é meu primeiro post)… então anexei em um arquivo txt.

O que já construí:

  • Fiz um formulário com três abas (Principal, Itens e Pagamento)

  • Na aba "Itens" usei um campo Typehead, que ao selecionar o item, preenche outros campos com o código e preço do produto

O que preciso:

  • Colocar um botão para inserir/editar vários itens em uma "tabela"

  • Deixando para gravar no banco apenas no final, quando o usuário mandar salvar o formulário principal

Gostaria, por favor, da ajuda de vocês para conseguir resolver essa 1a. grande dúvida !

Muito obrigado !

  • Coloquei a tela em anexo para vocês visualizarem melhor.

Gustavo Gonçalves

Gustavo,

Para inserir vários itens ao mesmo tempo, os campos do formulário, precisam está em formato de array().

Você pode fazer de 2 formas.

  1. Setar quantos campos somente vai precisar, por exemplo no máximo 20 campos, neste caso você irá usar o for() do PHP.

  2. Criar 1 campo, e os demais campos cria usando o jQuery, a função clone, assim você pode usar 2 ou 200 campos.

Exemplo de como usar o clone: http://www.mkyong.com/jquery/jquery-clone-example/

Para adicionar vários itens usando o for().

http://www.yiiframework.com/doc/guide/1.1/pt/form.table

Neste doc, ensina como fazer no formulário e no controller para coletar os dados.

Olá Newerton,

Obrigado pela dica.

Mas em função do layout da página pensei em fazer o seguinte para o cadastro de Itens:

  • Colocar uma GridView com um DataProvider vazio (inicialmente)

  • Veja que na minha imagem, coloquei um botão "Inserir"… através dele quero chamar uma função (addItem) no Controller para Validar os campos e Inserir os registros no DataProvider.

  • No momento de salvar o formulário todo (Ordem de Compras), lá na Action Create, faço um foreach no DataProvider dos Itens, criando um novo Model e aplicando o método Save().

Preciso de duas dicas, se possível com exemplo do código, pois já estou há mais de 8 horas pesquisando essa solução:

  • Como passar o DataProvider da view Create para a action addItem do Controller ?

  • Como devolver o DataProvider para a View e atualizar a GridView ?

Achei algumas coisas na internet, mas não consegui aplicar nenhuma.

Um abraço e muito obrigado !

Abaixo segue o trecho do código da View Create:




		<?php $this->widget('bootstrap.widgets.TbButton', array(

			'icon' => 'icon-plus',

			'size' =>'medium',

			'type' => 'warning',

			'buttonType' => 'ajaxLink',

			'url' => $this->createUrl('addItem'),

			'ajaxOptions'=>array('type'=>'POST', 'success'=>'allFine'),

			

		)); ?>




<div id='results'>...</div>

<script>

        function allFine(data) {

                // display data returned from action

                $("#results").html(data);

                // refresh your grid

                $.fn.yiiGridView.update('itens-grid');

        }

</script>


<?php

$this->widget('zii.widgets.grid.CGridView', array(

	'id'=>'itens-grid',

    'dataProvider'=>$dp_itens,

    'columns'=>array(

		'id_compra',

		'id_item',

		'id_produto',

		'qtde',

		'desconto',

		'valor',

    ),

));

?>



Bom dia a todos,

Atualizando …

Despois de muito custo consegui atualizar a GridView com um novo DataProvider. (abaixo vou explicar como fiz)

Agora preciso de ajuda para conseguir enviar o DataProvider ativo da View -> Controller.

Já li algo sobre usar Session, mas estou com dúvidas e não sei se é bom.

Outra opção seria fazer um Foreach na View, "desconstruindo" o Array em vários campos ocultos na página. Assim eu poderia recuperá-los através do $_POST dentro do Controller.

O que é melhor fazer ? Existe outra opção ?

Abaixo segue a explicação de como atualizar uma CGridView a partir de um novo DataProviderArray, quando se clica em algum botão ajax.

Na minha View Principal, tenho um botão Adicionar Itens:





<script>

        function allFine(data) {

                $("#div_itens").html(data);

        }

</script>




		<?php $this->widget('bootstrap.widgets.TbButton', array(

			'icon' => 'icon-plus',

			'size' =>'medium',

			'type' => 'warning',

			'buttonType' => 'ajaxLink',

			'url' => $this->createUrl('addItem'),

			'ajaxOptions'=>array('type'=>'POST',

			'success'=>'allFine', 

						),

			

		)); ?>




No final desta página, tenho o comando abaixo:




<?php echo $this->renderPartial('_griditens', array('dp_itens'=>$dp_itens,)); ?>



Criei uma outra View, "_griditens.php" que contém apenas a GridView dos Itens, pois ela recebe apenas o $dp_itens.

Isso foi importante, para não ter que fazer Render de todos os Models.

Coloquei os botões "Editar" e "Excluir" para manipular os valores do mesmo jeito da Action addItens.




<div class="row-fluid" id="div_itens">

	<div class="span10">		

		<?php 

		$this->widget('bootstrap.widgets.TbGridView',array(

			'id'=>'itens-grid',

			'template'=>"{items}",	

			'dataProvider'=>$dp_itens,

			'type'=>'striped bordered condensed',

			'columns'=>array(

		        array(

			            'name' => 'Produto',

			            'type' => 'raw',

			            'value' => 'CHtml::encode($data["produto"])'

			        ),				

		        array(

			            'name' => 'Qtde',

			            'type' => 'raw',

			            'value' => 'CHtml::encode($data["qtde"])'

			        ),				

		        array(

			            'name' => 'Valor',

			            'type' => 'raw',

			            'value' => 'CHtml::encode($data["valor"])'

			        ),				

		        array(

			            'name' => 'Desconto',

			            'type' => 'raw',

			            'value' => 'CHtml::encode($data["desconto"])'

			        ),				

		        array(

			            'name' => 'SubTotal',

			            'type' => 'raw',

			            'value' => 'CHtml::encode($data["subtotal"])'

			        ),				

				 array(

					'htmlOptions' => array('nowrap'=>'nowrap'),

					'class'=>'bootstrap.widgets.TbButtonColumn',

					'template'=>'{update}{delete}',

					'viewButtonUrl'=>null,

					'updateButtonUrl'=>null,

					'deleteButtonUrl'=>null,				 

                    'buttons'=>array(       

                                'update' => array(

                                  'url'=>'Yii::app()->controller->createUrl("editItem", array("id"=>$data["id"]))',

                                ),

                      			'delete' => array(

                                  //'url'=>'Yii::app()->controller->createUrl("ports/delete", array("id"=>$data[id],"command"=>"delete"))',

                                ),

                         	),				 

				),

			),

		)); 

		?> 

	</div>

</div>	




No meu controller, tenho a Action que é chamada:




	public function actionAddItem()

	{

	    if(!empty($_POST))


               // se precisar fazer um loop em vários campos do $_POST, usar este comando

	       //while(list($key, $val) = each($_POST)) {

	   	  //echo $key."=".$val."<br>";  // so para ver os valores, nao é necessario

	       //}

	   		


               // Cria um novo model limpo, da tabela itens

               $model_itens_add=new Compras02;

	       $model_itens_add->unsetAttributes();


	       $produto = $_POST['searchproduto'];

	       $model_itens_add->id_produto 	= $_POST['add_id'];

	       $model_itens_add->qtde 		= $_POST['add_qtde'];

	       $model_itens_add->desconto 	= $_POST['add_desc'];

	       $model_itens_add->valor 		= $_POST['add_valor'];

				

               ////////////////////////////

               // NESTE PONTO PRECISO TER O DATAPROVIDER ATUAL, PARA JUNTAR COM O NOVO REGISTRO

               ////////////////////////////


		// Dados do GridView

		$rawData=array(

			array('id'=>1, 

				  'produto'=>$produto, 

				  'qtde'=>$model_itens_add->qtde, 

				  'valor'=>$model_itens_add->valor, 

				  'desconto'=>$model_itens_add->desconto, 

				  'subtotal'=>($model_itens_add->qtde * $model_itens_add->valor) - $model_itens_add->desconto,

				  ), 

		);

		

       // Criando o novo Array para a Tabela GridView	 

       // or using: $rawData=User::model()->findAll();

       $dp_itens=new CArrayDataProvider($rawData, array(

           'id'=>'id',

           'sort'=>array(

               'attributes'=>array(

                   'produto',

               ),

           ), 

           'pagination'=>array(

               'pageSize'=>15,

           ),

       ));


		

                // Nao é necessário, deixei aqui pra testar depois o merge de arrays

                // Fazendo um Merge dos Arrays

		//$data = $dp_itens->getData();

		//$data[] = $model_itens_add;

		//$dp_itens->setData($data);		


		// Devolvendo os valores para a página		

		 $this->renderPartial('_griditens',array(

			 'dp_itens'=>$dp_itens,

		 ));		

	}



Espero que seja útil para alguém !!!

Coloquei a tela em anexo para vocês verem como ficou. Lógico que ainda falta formatar os campos valores e etc.

estou tentando fazer seu exemplo e nao vai por nada

Gostaria de mais detalhes de como fazer o exemplo. Não consegui também fazer.

Gostaria muito de saber se voce conseguiu preciso algo assim… se puder me ajudar grato desde já.