Multi model and multi step recording


#1

Hi. As everybody can see I need help too often.

I have a Sales Model, Controller and a few Views (at least, i pretend it !). Sales is related to Clients and Employers (companies where Clients work). At the same time, Clients, and Employers belongs to Countries, Regions, Counties and Cities. Clients have banks accounts as well.
The most important process my app need to manage is called “in site, sale events”, on wich, we need:

  1. get from a view.ctp the Employer where the sale operative will take efect;
  2. if the Employer is a new one, need to be able of insert the new entity using a modal window without leave the actual view;
  3. If a new Employer was recorded (according to step 2), we’ll need to do the same with the final Clients
  4. Once the Employer is determined and the clients have been properly saved in Clients model, we need to add new sales until “sale operative” is completed.

So here are the problems I cant not solve:
a) How to add new records of another Controller/Model?.
b) How to get the needed variables (Employer id and name) selected in a previos view?
c) How to keep saving sales records withot exit of the “sale operative” view.

I’ve tried everything i can (wich obviously hasn’t been enough), so, I really need help


#2

Hi,
Kindly supply the code that you do have so people can help to correct it.
As for working with multiple classes, the best way is;
1- To add foreign key (FK) relations in the database
2- Specify these relationships in the Table files (automatically baked if they exist as FK relations in database)
I would also like to recommend to first design the solution;
1- Create an entity relation diagram (ERD)
2- Create business logic or process flow diagrams.
These will also help other people to contribute to your solutions much easier. From a verbal description without context, it’s much harder to understand what you want to achieve and where it doesn’t work.


#3

Hi, everyone, lafeber;

Actually, I am using foreign keys and my models looks well “baked”. Anyway, I can’t do what I need.

I just need someone to guide me a little about the “How to do” of cakephp 3.5. Of course I do not intend somebody else to do “the work”…

I put some comments directly on my code so people can have an idea on what is happening rigth now.

For better understanding of business logic or process flow, please double-check my initial post.

I’ll try to do my best, so I warn everybody that in my hazing, I’m afraid I’ve been “kicking” the MVC model … I beg your pardon …

  1. Controller:
<?php namespace App\Controller; use App\Controller\AppController; /** * Sales Controller * * @property \App\Model\Table\SalesTable $Sales * * @method \App\Model\Entity\Sale[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) */ class SalesController extends AppController { /** * PreOperativo method * This method aims to establish the basic data necessary to execute a "Sales Operative" * (many sales at the same time, in the facilities of an Employer) * @return \Cake\Http\Response|void */ public function preOperativo() { $companies = $this->Sales->Companies->find('list', ['limit' => 200]); $clients = $this->Sales->Clients->find('list', ['limit' => 10000]); $employers = $this->Sales->Employers->find('list', ['limit' => 6000]); $companyBranches = $this->Sales->Companybranches->find('list', ['limit' => 200]); $sale = $this->Sales->find('list'); // DETERMINE Company AND CompanyBranch from Authorized user array $CompanyCode = $this->request->session()->read('Auth.User.company_code'); $CompanyBranch = $this->request->session()->read('Auth.User.company_branch'); $this->loadModel('Companies'); /* We obtain the Company name field and assign it to $ CompanyName for heading title purposes, etc. */ $query = $this->Companies->find('list', array('fields' => array('name')), ['conditions',['id =' => $CompanyCode]]); $results = iterator_to_array($query); $Company = $results[0]; $this->set('CompanyName', $Company); $this->loadModel('CompanyBranches'); /* We obtain the CompanyBranch name field and assign it to $BranchName for heading title purposes, etc. */ $query1 = $this->CompanyBranches->find('list', array('fields' => array('name')), ['conditions',['id =' => $CompanyBranch]]); $results1 = iterator_to_array($query1); $Branch = $results1[0]; $this->set('BranchName', $Branch); // if we need to add new Clients or Employer, the related Models are loaded $this->loadModel('Countries'); $this->loadModel('Counties'); $this->loadModel('Cities'); $this->loadModel('Regions'); $this->loadModel('Banks'); $this->loadModel('Employers'); // if we need to add a new Employer: $employer = $this->Employers->newEntity(); if ($this->request->is('post')) { $employer = $this->Employers->patchEntity($employer, $this->request->getData()); if ($this->Employer->save($employer)) { $this->Flash->flash('El Empleador ha sido registrado con éxito!', ['params' => ['type' => 'success']]); } else { $this->Flash->flash('El Empleador no pudo ser registrado!', ['params' => ['type' => 'success']]); } } /* Right now, this doesn't work. Seems like the script try to add a new record but in the "Sale" entity instead of in the "Employer" entity. Of course doesn't insert any record anywhere*/ $this->loadModel('Clients'); $client = $this->Clients->newEntity(); if ($this->request->is('post')) { $client = $this->Clients->patchEntity($client, $this->request->getData()); if ($this->Client->save($client)) { $this->Flash->flash('El Cliente ha sido registrado con éxito!', ['params' => ['type' => 'success']]); } else { $this->Flash->flash('El Cliente no pudo ser registrado!', ['params' => ['type' => 'success']]); } } $EmployerName = ""; $countries = $this->Countries->find('list', ['limit' => 400]); $regions = $this->Regions->find('list', ['limit' => 200]); $counties = $this->Counties->find('list', ['limit' => 200]); $cities = $this->Cities->find('list', ['limit' => 400]); $banks = $this->Banks->find('list', ['limit' => 200]); $sale = $this->Sales->find('list'); $this->set( compact( 'sale', 'client', 'employer', 'clients', 'companies', 'companyBranches', 'employers', 'countries', 'regions', 'counties', 'cities', 'banks', 'CompanyName', 'CompanyCode', 'Order', 'CompanyBranch', 'Fech', 'NuevoCliente', 'NuevoEmpleador', 'NuevaOrden', 'EmployerName' ) ); } /** * Operativo method * This method aims to execute a "Sales Operative" * (many sales at the same time, in the facilities of an Employer) * @return \Cake\Http\Response|void */ public function operativo() { // DETERMINE Company AND CompanyBranch from Authorized user array $CompanyCode = $this->request->session()->read('Auth.User.company_code'); $CompanyBranch = $this->request->session()->read('Auth.User.company_branch'); $this->loadModel('Companies'); /* We obtain the Company name field and assign it to $ CompanyName for heading title purposes, etc. */ $query = $this->Companies->find('list', array('fields' => array('name')), ['conditions',['id =' => $CompanyCode]]); $results = iterator_to_array($query); $Company = $results[0]; $this->set('CompanyName', $Company); $this->loadModel('CompanyBranches'); /* We obtain the CompanyBranch name field and assign it to $BranchName for heading title purposes, etc. */ $query1 = $this->CompanyBranches->find('list', array('fields' => array('name')), ['conditions',['id =' => $CompanyBranch]]); $results1 = iterator_to_array($query1); $Branch = $results1[0]; $this->set('BranchName', $Branch); // The field order_date of Sale Entity takes value of current date $Fecha = date('Y/m/d'); // String conversions to construct the field "work-order" of "Sale" $year=str_pad(substr($Fecha, 2, 2), 2, "0", STR_PAD_LEFT); $month=str_pad(substr($Fecha, 5, 2), 2, "0", STR_PAD_LEFT); $day=str_pad(substr($Fecha, 8, 2), 2, "0", STR_PAD_LEFT); $Fech = $year . $month . $day; $CompanyCode = str_pad($CompanyCode, 3, "0", STR_PAD_LEFT); $CompanyBranch = str_pad($CompanyBranch, 2, "0", STR_PAD_LEFT); $countries = $this->Countries->find('list', ['limit' => 400]); $regions = $this->Regions->find('list', ['limit' => 200]); $counties = $this->Counties->find('list', ['limit' => 200]); $cities = $this->Cities->find('list', ['limit' => 400]); $banks = $this->Banks->find('list', ['limit' => 200]); $companies = $this->Sales->Companies->find('list', ['limit' => 200]); $clients = $this->Sales->Clients->find('list', ['limit' => 10000]); $employers = $this->Sales->Employers->find('list', ['limit' => 6000]); $companyBranches = $this->Sales->Companybranches->find('list', ['limit' => 200]); // we add a new "order" in "CompanyOrder" entity. Each sale is associated to an order number // (CompanyOrder->id) (This works 2018/03/02) if ($this->request->is('post')) { $sale = $this->Sales->newEntity(); $this->loadModel('CompanyOrders'); $companyorder = $this->CompanyOrders->newEntity(); $companyorder->company_id = $CompanyCode; $this->set('company_id', $CompanyCode); if ($this->CompanyOrders->save($companyorder)) { // The $companyorder entity contains the id now $Order = $companyorder->id; $this->set('company_order_id', $companyorder->id); $Order = str_pad($Order, 2, "0", STR_PAD_LEFT); $sale->company_id = $CompanyCode; $sale->company_order_id = $companyorder->id; $this->Flash->flash('Se creó una nueva orden de trabajo.', ['params' => ['type' => 'warning']]); } else { $this->Flash->flash('No se pudo crear una nueva orden de trabajo.', ['params' => ['type' => 'danger']]); } // 2018/03/02: until now the following does not work. Seem like it never go in there... if ($this->Sale->save($this->request->data)) { $this->Flash->flash('La venta ha sido registrada con éxito!', ['params' => ['type' => 'success']]); $this->redirect(array('datos-venta')); } else { $this->Flash->flash('La venta no pudo ser registrada!', ['params' => ['type' => 'success']]); } } $this->set(compact('sale', 'clients', 'companies', 'companyBranches', 'employers', 'countries', 'regions', 'counties', 'cities', 'banks', 'CompanyName', 'CompanyCode', 'Order', 'Fech', 'client', 'employer', 'companybranch', 'CompanyBranch', 'EmployerName')); } /** 2) Table <?php namespace App\Model\Table; use Cake\ORM\Query; use Cake\ORM\RulesChecker; use Cake\ORM\Table; use Cake\Validation\Validator; /** * Sales Model * * @property \App\Model\Table\CompaniesTable|\Cake\ORM\Association\BelongsTo $Companies * @property |\Cake\ORM\Association\BelongsTo $CompanyBranches * @property \App\Model\Table\MandatesTable|\Cake\ORM\Association\BelongsTo $Mandates * @property |\Cake\ORM\Association\BelongsTo $CompanyOrders * @property \App\Model\Table\ClientsTable|\Cake\ORM\Association\BelongsTo $Clients * @property \App\Model\Table\EmployersTable|\Cake\ORM\Association\BelongsTo $Employers * @property \App\Model\Table\MandatesTable|\Cake\ORM\Association\HasMany $Mandates * * @method \App\Model\Entity\Sale get($primaryKey, $options = []) * @method \App\Model\Entity\Sale newEntity($data = null, array $options = []) * @method \App\Model\Entity\Sale[] newEntities(array $data, array $options = []) * @method \App\Model\Entity\Sale|bool save(\Cake\Datasource\EntityInterface $entity, $options = []) * @method \App\Model\Entity\Sale patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) * @method \App\Model\Entity\Sale[] patchEntities($entities, array $data, array $options = []) * @method \App\Model\Entity\Sale findOrCreate($search, callable $callback = null, $options = []) */ class SalesTable extends Table { /** * Initialize method * * @param array $config The configuration for the Table. * @return void */ public function initialize(array $config) { parent::initialize($config); $this->setTable('sales'); $this->setDisplayField('id'); $this->setPrimaryKey('id'); $this->belongsTo('Companies', [ 'foreignKey' => 'company_id', 'joinType' => 'INNER' ]); $this->belongsTo('CompanyBranches', [ 'foreignKey' => 'company_branch_id', 'joinType' => 'INNER' ]); $this->belongsTo('CompanyOrders', [ 'foreignKey' => 'company_order_id', 'joinType' => 'INNER' ]); $this->belongsTo('Clients', [ 'foreignKey' => 'client_id', 'joinType' => 'INNER' ]); $this->belongsTo('Employers', [ 'foreignKey' => 'employer_id', 'joinType' => 'INNER' ]); $this->hasMany('Mandates', [ 'foreignKey' => 'sale_id' ]); } /** * Default validation rules. * * @param \Cake\Validation\Validator $validator Validator instance. * @return \Cake\Validation\Validator */ public function validationDefault(Validator $validator) { $validator ->integer('id') ->allowEmpty('id', 'create'); $validator ->scalar('work_order') ->maxLength('work_order', 18) ->requirePresence('work_order', 'create') ->notEmpty('work_order'); $validator ->date('order_date') ->requirePresence('order_date', 'create') ->notEmpty('order_date'); $validator ->decimal('order_amount') ->requirePresence('order_amount', 'create') ->notEmpty('order_amount'); $validator ->decimal('cash_amount') ->allowEmpty('cash_amount'); $validator ->decimal('card_amount') ->allowEmpty('card_amount'); $validator ->decimal('pac_amount') ->allowEmpty('pac_amount'); $validator ->integer('payment_qty') ->requirePresence('payment_qty', 'create') ->notEmpty('payment_qty'); return $validator; } /** * Returns a rules checker object that will be used for validating * application integrity. * * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. * @return \Cake\ORM\RulesChecker */ public function buildRules(RulesChecker $rules) { $rules->add($rules->existsIn(['company_id'], 'Companies')); $rules->add($rules->existsIn(['company_branch_id'], 'CompanyBranches')); $rules->add($rules->existsIn(['mandate_id'], 'Mandates')); $rules->add($rules->existsIn(['company_order_id'], 'CompanyOrders')); $rules->add($rules->existsIn(['client_id'], 'Clients')); $rules->add($rules->existsIn(['employer_id'], 'Employers')); return $rules; } } 3) pre_operativo.ctp (wich is called from a index.ctp link)
<?= $this->Html->link('Volver', ['action' => 'index']) ?>

Preparando Operativo de Venta de <?= $CompanyName . " (" . $BranchName .")" ?>

<?= $this->Form->create($sale) ?> <?= $this->Form->create($sale, ['novalidate']) ?> <?= $this->form->control('employer_id', ['label' =>'Empresa Empleadora', 'option' => $employers]) ?> Registrar nueva Empresa Empleadora?
×

Empleador Nuevo

<?php $NuevoEmpleador = true; ?> <?= $this->Form->create($employer) ?> <?= $this->Form->create($employer, ['novalidate']) ?>
<?= $this->element('employers/fields') ?>
<?= $this->Form->button('Aceptar') ?> <?= $this->Form->end() ?>
Close
Registrar nuevo Cliente?
×

Cliente Nuevo

<?php $NuevoCliente = true; ?> <?= $this->Form->create($client) ?> <?= $this->Form->create($client, ['novalidate']) ?>
<?= $this->element('clients/fields') ?>
<?= $this->Form->button('Aceptar') ?> <?= $this->Form->end() ?>
Close
<div class="row">
    <div class="row">
    <!-- once we have the needed data requiered for "sales operative" execution: -->
    <?php echo $this->Html->link(
          $this->Form->button("Ejecuta Operativo", ["type" => "button", "class"=>"btn btn-dark 
          btn-theme-colored btn-flat mr-5"]
        ),
        array(
            'action' => 'operativo'
        ),
        array(
            'escape' => false
    ));?>
    </div>
</div>
<?= $this->Form->end() ?>
  1. operativo.ctp (wich is called from a pre-operativo.ctp link)
.cabecera{ padding:15px; } .cabecera h2, h1{ text-align:center; color:blue; } .caja { padding:0 15px; } <?php $workOrder = $CompanyCode."-".$CompanyBranch."-".$Fech."-".$Order; $sale->workorder = $workOrder; ?>

<?= $CompanyName?> . ": "Operativo de Venta en <?=$EmployerName?>

<?= $this->Form->create($sale) ?> <?= $this->Form->create($sale, ['novalidate']) ?>
<?= h('No. Mandato/Orden: ' . $workOrder) ?>
<?= h('Fecha: ' . date('d/m/Y')) ?>
<?= $this->form->control('client_id', ['label' => 'Cliente', 'option' => $clients]) ?>
<?= $this->form->control('order_amount', ['label' =>'Total Orden']) ?>
<?= $this->form->control('cash_amount', ['label' =>'Monto Efectivo']) ?>
<?= $this->form->control('card_amount', ['label' =>'Monto en Tarjetas']) ?>
<?= $this->form->control('pac_amount', ['label' =>'Monto en PACs']) ?>
<?= $this->form->control('payments_number', ['label' =>'No. de Cuotas']) ?>
<?= $this->Form->button('Cancelar', ['type' => 'reset']) ?> <?= $this->Form->button('Aceptar', ['type' => 'submit']) ?> <?= $this->Form->button('Fin Operativo', ['type' => 'button']) ?> <?= $this->Form->end() ?>

#4

P.S.

When I try to add new clients or employers from the modal windows, I get this error msg:
“Call to a member function find () on boolean”

BTW, sorry about the code presentation… I just don´t know how to insert it here!!!